在最坏的情况下,在大小为n
的内存的一个部分(这是正确的术语?)上,链接列表需要O(n)
时间来分配合适大小的内存块。< / p>
但是,如果malloc
是基于树的,例如,间隔树,则只需要O(logn)
时间。此外,树可以满足这样的要求而没有额外的时间(就时间复杂度而言)为"Find the smallest block of free memory whose size is larger them
x "
,"Always allocate on the borders of free memory"
和"Free only a part of the allocated memory"
。一个缺点可能是释放内存需要O(logn)
时间。
由于
PS。我已经看到了Data structures for traversable memory pool这个问题,但作者似乎并没有想到这个问题。
答案 0 :(得分:3)
我不知道答案,但这里有一些想法:
绝对没有malloc
以特定方式实施的要求。但是,在最坏的情况下,不平衡树与链表一样糟糕。平衡的链表是更多的维护。每个节点有两个链接的树也比单链表占用更多内存。删除链表中的节点更容易,最后插入非常容易。
在大多数系统中,每free
(几乎)只有一个malloc
- 所以如果你通过让另一个更慢来制作一个更快,那么你获得的收益很少。
“下一个分配与前一个分配相同”也是相对常见的,这意味着如果最后一个分配是列表中的第一个,则它是O(1)操作。
在实时系统中,存储桶通常用于分配,因此存在许多固定大小,并且每次从主堆分配某些内容时,大小将四舍五入到最接近的较大大小,并且释放它进入那个大小的桶(这是一个链表)。如果已存在该大小的自由元素,则使用该分配。除了分配/自由为O(1)的速度之外,这还有减少碎片的好处 - 并非完全不可能“将所有堆碎成小块,然后没有留下任何大块”,但它至少不是通过简单地每次分配一个字节来占用大部分内存,直到你在一次分配中有一半的堆大小。
(另外,在Linux的GLIBC中,超过特定大小的分配根本不会在链接列表中结束 - 它们直接通过mmap
分配,并在munmap
时以free
释放。被称为)
最后,算法的复杂性并非一切 - 在现实生活中,它是在重要事物上花费的实际时间 - 即使算法具有O(n)但每个操作都很快,它可以击败O(logn)。同样,特别是在C ++中,小分配占据主导地位,这意味着每个节点更多内存的开销是一个重要因素。
答案 1 :(得分:0)
没有说明malloc需要基于链表的规范。在平台之间,实施可能会改变。在一个平台上,速度可能是至关重要的,并且可以实现树,在另一个平台上,内存更昂贵,并且使用链表(或类似)来节省尽可能多的内存。