如何将完全未使用的内存分段?

时间:2013-10-15 05:39:03

标签: c memory-fragmentation

在Windows 7 64位上执行的C代码示例(取自http://bugs.python.org/issue19246),在32位模式下编译时

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>


int create_huge_linked_list(void **last_item) {
    int i;
    void *prev_item = NULL;

    for(i = sizeof(void *); i < 1000000; i++) {
        void *new_item = malloc(i);
        if(new_item == NULL) {
            break;
        }
        *(void **)new_item = prev_item;
        prev_item = new_item;
    }
    *last_item = prev_item;
    return i;
}

void free_linked_list(void *last_item) {
    while(last_item != NULL) {
        void *prev_item = *(void **)last_item;
        free(last_item);
        last_item = prev_item;
    }
}

int stress_heap() {
    void *last_item;
    int amount = create_huge_linked_list(&last_item);
    free_linked_list(last_item);
    return amount;
}

void stress_twice(void) {
    int first = stress_heap();
    int second = stress_heap();
    printf("%i %i %f%%\n", first, second, 100.0 * second / first);
}

void stress_and_alloc_1_mb() {
    void *ptr;

    ptr = malloc(1000000);
    if(ptr != NULL) {
        printf("Successfully allocated 1 MB before stress\n");
        free(ptr);

        stress_heap();

        ptr = malloc(1000000);
        if(ptr != NULL) {
            printf("Successfully allocated 1 MB after stress\n");
            free(ptr);
        } else {
            printf("Failed to allocate 1 MB after stress\n");
        }
    } else {
        printf("Failed to allocate 1 MB before stress\n");
    }
}

int main() {
    stress_and_alloc_1_mb();
    stress_twice();
    return 0;
}

输出:

Successfully allocated 1 MB before stress
Failed to allocate 1 MB after stress
64855 64857 100.003084%

结果可能被解释为:在整个内存分配然后释放它之后,进程的内存碎片如此糟糕,没有长度为1 MB的块。 但是,压力过程可以连续重复,没有记忆错误。

问题是:

  1. 如果内存完全未使用,内存可以如何分段?
  2. 如何为该过程修复内存碎片?

1 个答案:

答案 0 :(得分:3)

#1

这是一个有趣的问题,因为我们从未真正谈论过分散的使用内存(现在让我们忽略缓存局部性)。当所述内存可以再次分发时,内存碎片成为一个问题,但是先前的内存分配将内存池分成更小的块需要将块连接在一起。

我认为你问这个问题的原因是因为你已经习惯了最坏情况的例子,其中没有这样的连续内存块存在而没有移动任何东西。但即使在非最坏的情况下,检测潜在的碎片化操作也是一个非常困难的问题,导致分配器阻塞问题的实例,人类可以很容易地看到解决方案。

但要回答你的问题,请考虑这个分配的内存块:

aaaabbbbcccc

现在ac被释放:

....bbbb....

现在b被释放了:

....____....

现在我们在内存池中有三个连续的单独内存块 - 它需要特殊的代码来检测它,显然分配器会对此产生阻塞。

#2

答案很简单:对内存池进行碎片整理。这个问题多么容易/困难取决于使用什么类型的分配器以及它有多少簿记。