0

次の C コードの例 ( http://bugs.python.org/issue19246から取得) は、32 ビット モードでコンパイルされている間に、Windows 7 64 ビットで実行されます。

#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. そのプロセスのメモリの断片化をどのように修正できますか?
4

1 に答える 1

3

#1

断片化された使用中のメモリについて実際に話したことがないため、これは一種の面白い質問です (ここでは、キャッシュの局所性を無視しましょう)。メモリの断片化は、前述のメモリを再度分散できるようになったときに問題になりますが、メモリ プールを小さなチャンクに分割する以前のメモリ割り当てでは、チャンクを結合する必要があります。

あなたがこの質問をする理由は、あなたが最悪のケースの例に慣れているからだと思います.何も動かさないと、そのような連続したメモリブロックは存在しません. しかし、最悪の場合でなくても、潜在的なデフラグ操作を検出するのが非常に難しい問題になる可能性があり、人間が簡単に解決策を見つけることができる問題のインスタンスでアロケータがチョークする原因になります。

しかし、あなたの質問に答えるために、この割り当てられたメモリのチャンクを考えてみましょう:

aaaabbbbcccc

さあac解放されましょう:

....bbbb....

そして今b解放されます:

....____....

これで、メモリ プールに 3 つの連続した個別のメモリ チャンクができました。これを検出するには特別なコードが必要であり、明らかにアロケータがこれをチョークします。

#2

これに対する答えは簡単です。メモリ プールをデフラグします。この問題がどれほど簡単か難しいかは、使用されるアロケーターの種類と、それがどの程度簿記を行うかによって異なります。

于 2013-10-15T05:55:00.350 に答える