1

现在我在看C的接口和实现。图四是内存管理。它说alighment保证了任何类型的数据都可以存储在Mem_alloc函数返回的块中。我怎么理解这句话?有必要吗?管理内存时对齐?

对齐代码如下:

union align {
#ifdef MAXALIGN
        char pad[MAXALIGN];
#else
        int i;
        long l;
        long *lp;
        void *p;
        void (*fp)(void);
        float f;
        double d;
        long double ld;
#endif
void *Mem_alloc(long nbytes, const char *file, int line){
        struct descriptor *bp;
        void *ptr;
        assert(nbytes > 0);
        nbytes = ((nbytes + sizeof (union align) - 1)/
                (sizeof (union align)))*(sizeof (union align));
        for (bp = freelist.free; bp; bp = bp->free) {
                if (bp->size > nbytes) {
                        bp->size -= nbytes;
                        ptr = (char *)bp->ptr + bp->size;
                        if ((bp = dalloc(ptr, nbytes, file, line)) != NULL) {
                                unsigned h = hash(ptr, htab);
                                bp->link = htab[h];
                                htab[h] = bp;
                                return ptr;
                        } else
                                {
                                        if (file == NULL)
                                                RAISE(Mem_Failed);
                                        else
                                                Except_raise(&Mem_Failed, file, line);
                                }
                }
                if (bp == &freelist) {
                        struct descriptor *newptr;
                        if ((ptr = malloc(nbytes + NALLOC)) == NULL
                        ||  (newptr = dalloc(ptr, nbytes + NALLOC,
                                        __FILE__, __LINE__)) == NULL)
                                {
                                        if (file == NULL)
                                                RAISE(Mem_Failed);
                                        else
                                                Except_raise(&Mem_Failed, file, line);
                                }
                        newptr->free = freelist.free;
                        freelist.free = newptr;
                }
        }
        assert(0);
        return NULL;
}
    };

 void *Mem_resize(void *ptr, long nbytes,
        const char *file, int line) {
        struct descriptor *bp;
        void *newptr;
        assert(ptr);
        assert(nbytes > 0);
        if (((unsigned long)ptr)%(sizeof (union align)) != 0
        || (bp = find(ptr)) == NULL || bp->free)
                Except_raise(&Assert_Failed, file, line);
        newptr = Mem_alloc(nbytes, file, line);
        memcpy(newptr, ptr,
                nbytes < bp->size ? nbytes : bp->size);
        Mem_free(ptr, file, line);
        return newptr;
}  

我如何理解这些代码?为什么在调整空间大小时需要 if (((unsigned long)ptr)%(sizeof (union align)) != 0 ?

4

1 回答 1

1

CPU 在处理数据方面有局限性。例如,对于 32 位 CPU,指针通常必须是 4 字节对齐的,而对于 64 位 CPU,指针通常必须是 8 字节对齐的。此外,在允许的情况下,在未对齐的边界上加载和存储数据可能会降低性能。例如,CPU 可能能够从奇数地址加载,但它需要两倍的周期。这通常是因为内存硬件已针对在 4、8 或 16 字节边界上抓取数据进行了优化,并且必须在一个周期内加载数据字的下部,然后在下一个周期内加载上部。

因此,在实现编译器时,您希望它在具有这些对齐需求的 CPU 上运行良好。

有关英特尔 IA-64 对齐要求的示例,请参见此处:

  • 在任意地址对齐 8 位数据
  • 对齐 16 位数据以包含在对齐的四字节字中
  • 对齐 32 位数据,使其基地址为 4 的倍数
  • 对齐 64 位数据,使其基地址为 8 的倍数
  • 对齐 80 位数据,使其基地址为 16 的倍数
  • 对齐 128 位数据,使其基地址为 16 的倍数
于 2013-10-15T03:17:42.927 回答