具有恒定时间操作的智能内存管理?


18

让我们考虑一个内存段(可以在需要时增大或缩小文件的大小,就像文件一样),您可以在该内存段上执行两个涉及固定大小块的基本内存分配操作:

  • 分配一个块
  • 释放先前已分配的不再使用的块。

同样,作为一项要求,不允许内存管理系统在当前分配的块之间移动:它们的索引/地址必须保持不变。

最幼稚的内存管理算法将增加一个全局计数器(初始值为0),并将其新值用作下一个分配的地址。但是,当只剩下几个分配的块时,这绝不允许缩短段。

更好的方法:保留计数器,但维护一个释放块列表(可以在固定时间内完成),并在不为空的情况下将其用作新分配的源。

接下来是什么?在保持恒定的时间分配和解除分配约束的情况下,有什么办法可以使内存段尽可能地短而可以完成?

(目标可能是使用最小的地址跟踪当前未分配的块,但是在恒定时间内似乎不可行……)


列表的检查会不会不再是固定时间的,因为列表可能会由于之前进行的某些分配/分配而增加或缩小?
2012年

@Sim,我假设它是一个链表,使用它,操作将为,因为您始终只使用头部。Øñ
svick 2012年

我认为您的“更好的方法”已经使用了最佳的内存量,即,如果有空闲块,它将永远不会分配额外的内存。您如何看待“聪明”的方法会对此有所改善?您是说它应该分配在开始位置附近,以便有更大的机会在释放之后缩小该段吗?
svick 2012年

@Sim:抱歉,也许我应该使用术语堆栈(但我认为这可能会造成混淆),“ deallocate”是推式,而“ allocate”是弹出式的,或者在失败的情况下,只能使用计数器递增。两者都是固定的时间。
斯特凡希门尼斯

您是否有实时限制,还是可以按固定时间摊销?答案可能完全不同。
吉尔(Gilles)'所以

Answers:


11

对于固定大小的块,您所描述的是一个空闲列表。这是一种非常常见的技术,但有以下不同之处:空闲块列表存储在空闲块本身中。在C代码中,它看起来像这样:

static void *alloc_ptr = START_OF_BIG_SEGMENT;
static void *free_list_head = NULL;

static void *
allocate(void)
{
    void *x;

    if (free_list_head == NULL) {
        x = alloc_ptr;
        alloc_ptr = (char *)alloc_ptr + SIZE_OF_BLOCK;
    } else {
        x = free_list_head;
        free_list_head = *(void **)free_list_head;
    }
    return x;
}

static void
release(void *x)
{
    *(void **)x = free_list_head;
    free_list_head = x;
}

只要所有分配的块具有相同的大小,并且该大小是指针大小的倍数,此方法就可以很好地保持对齐。分配和释放是固定时间的(即与内存访问和基本添加相同的恒定时间),在现代计算机中,内存访问可能涉及高速缓存未命中甚至虚拟内存,因此涉及磁盘访问,因此“恒定时间”可能会很大)。没有内存开销(没有额外的每个块指针或类似的东西;分配的块是连续的)。同样,仅在一次必须分配许多块的情况下,分配指针才会到达给定点:由于分配倾向于使用空闲列表,因此仅当当前指针下方的空间已满时,分配指针才会增加。从这个意义上讲 技术。

减少释放后的分配指针可能会更加复杂,因为只有遵循空闲列表(以不可预测的顺序遍历它们)才能可靠地标识空闲块。如果在可能的情况下减小大片段的大小对您很重要,那么您可能希望使用另一种技术,但会增加开销:在任何两个已分配的块之间放置一个“孔”。这些孔与一个双链表按内存顺序链接在一起。您需要孔的数据格式,以便可以通过知道孔的结束位置来确定孔的起始地址,如果知道孔在内存中的起始位置,还可以找到孔的大小。然后,当释放一个块时,您将创建一个孔,该孔将与下一个孔和上一个孔合并,从而重建(仍在恒定时间内)所有孔的有序列表。那么,每个分配的块的开销大约是两个指针大小的字。但是,以该价格,您可以可靠地检测到“最终孔”的发生,即减小大段尺寸的机会。

有许多可能的变化。很好的介绍性论文是《动态存储分配: Wilson 等人的调查和重要评论》。


4
您如何在恒定时间内找到最接近释放位置的孔?
拉斐尔

1
在我描述的第二种方法中,空洞是标题(一对指针,用于空洞列表)以及零,一个或多个数据块的空间。在任何两个分配的块之间,始终有一个孔,即使它是仅由孔头组成的微孔也是如此。因此,找到最近的孔很容易:它们恰好在插槽的前面和后面。当然,微孔不会成为空闲列表(有资格分配的孔列表)的一部分。另一种查看方法是在每个块和每个(非微)孔中添加标题(在16位Ms-Dos下分配的工作方式是这样)。
Thomas Pornin 2012年

4

这个答案是关于通用内存管理技术的。我错过了这个问题,询问所有块具有相同大小(并对齐)的情况。


您应该知道的基本策略是“最适合”,“最不适合”,“最适合”和伙伴系统。我曾经为我所教的课程写过一个简短的摘要,希望它是可读的。我指的是一项相当详尽的调查

在实践中,您将看到这些基本策略的各种修改。但是这些都不是真正恒定的时间!我认为在使用有限数量的内存的最坏情况下这是不可能的。


有趣的是,我必须详细阅读。但是,这些系统似乎专门处理非恒定大小的分配,这不是我面临的问题。
斯特凡希门尼斯

对。抱歉,我读得太快了。
rgrig'3

Ølgñ

s /最小空闲块/最小地址处的空闲块/
rgrig 2012年

2

您可能需要查看摊销分析,尤其是动态数组。即使实际上并不是每个步骤都在一定的时间内真正完成操作,但从长远来看,情况确实如此。


2
动态数组将如何准确地帮助分配内存?
svick 2012年

您会使用相同类型的算法来(取消)分配连续单元的块吗?您的整个文件将是越来越大的块的链接列表。
gallais 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.