57

私は自分のマシン(1 Gb RAM 160 Gb HD Windowsプラットフォーム)で最大の範囲でmallocできるメモリの量を把握しようとしていました。

mallocが割り当てることができる最大メモリは(ヒープ上の)物理メモリに制限されていることを読みました。

また、プログラムがメモリの消費量を特定のレベルに超えると、他のアプリケーションが必要なメモリを十分に取得できないため、コンピュータは動作を停止します。

確認のために、Cで小さなプログラムを作成しました。

int main(){  
    int *p;
    while(1){
        p=(int *)malloc(4);
        if(!p)break;
    }   
}

メモリの割り当てが失敗してループが壊れる時期があることを期待していましたが、無限ループであったため、コンピュータがハングしました。

私は約1時間待って、最終的にコンピューターを強制的にシャットダウンしなければなりませんでした。

いくつかの質問:

  • mallocはHDからもメモリを割り当てますか?
  • 上記の行動の理由は何でしたか?
  • なぜどの時点でもループブレークしなかったのですか?
  • 割り当てに失敗しなかったのはなぜですか?
4

8 に答える 8

54

malloc割り当てることができる最大メモリは(ヒープ上の)物理メモリに制限されていることを読みました。

間違った例:ほとんどのコンピューター/ OSは、ディスクスペースに支えられた仮想メモリをサポートしています。

いくつかの質問:mallocHDDからもメモリを割り当てますか?

mallocOSに問い合わせると、OSはディスク容量を使用する可能性があります。

上記の動作の理由は何でしたか?ループがいつでも壊れなかったのはなぜですか?

割り当てに失敗しなかったのはなぜですか?

一度に要求したのは少なすぎます。ループは最終的には壊れていたでしょう(仮想メモリと物理メモリが大幅に過剰になり、その結果、ディスクアクセスが非常に頻繁に発生したために、マシンの速度が低下した後、「スラッシング」と呼ばれる問題が発生しました。 ")しかし、それはそれ以前にあなたの忍耐力を使い果たしました。代わりに、たとえば一度に1メガバイトを取得してみてください。

プログラムがメモリの消費量を特定のレベルに超えると、他のアプリケーションが必要なメモリを十分に取得できないため、コンピュータは動作を停止します。

完全に停止する可能性は低いですが、通常は数マイクロ秒かかる操作が(たとえば)数十ミリ秒かかる場合、これらの4桁は、コンピュータが基本的に停止したかのように感じさせる可能性があります。 1分は1週間かかる場合があります。

于 2010-05-09T16:38:18.627 に答える
26

このスレッドは古いことは知っていますが、自分で試してみることをいとわない人は、このコードを切り取って使用してください

#include <stdlib.h>

int main() {
int *p;
while(1) {
    int inc=1024*1024*sizeof(char);
    p=(int*) calloc(1,inc);
    if(!p) break;
    }
}

走る

$ gcc memtest.c
$ ./a.out

実行すると、このコードはカーネルによって強制終了されるまでRAMをいっぱいにします。「遅延評価」を防ぐために、mallocの代わりにcallocを使用します。このスレッドからのアイデア: Mallocメモリの質問

このコードはすぐにRAM(4Gb)をいっぱいにし、約2分で20Gbスワップパーティションが死ぬ前にいっぱいになりました。もちろん64ビットLinux。

于 2011-01-19T13:30:26.723 に答える
10

/proc/sys/vm/overcommit_memoryLinuxで最大値を制御します

たとえば、Ubuntu 19.04では、を使用して実装されていることが簡単にわかりますmallocmmap(MAP_ANONYMOUSstrace

次に、最大割り当てを制御するman proc方法について説明します。/proc/sys/vm/overcommit_memory

このファイルには、カーネル仮想メモリアカウンティングモードが含まれています。値は次のとおりです。

  • 0:ヒューリスティックなオーバーコミット(これがデフォルトです)
  • 1:常にオーバーコミットし、チェックしない
  • 2:常にチェックし、オーバーコミットしない

モード0では、MAP_NORESERVEを使用したmmap(2)の呼び出しはチェックされず、デフォルトのチェックは非常に弱く、プロセスが「OOM-killed」になるリスクがあります。

モード1では、カーネルは、メモリが実際になくなるまで、常に十分なメモリがあるふりをします。このモードの使用例の1つは、大規模なスパースアレイを採用する科学計算アプリケーションです。2.6.0より前のLinuxカーネルバージョンでは、ゼロ以外の値はモード1を意味します。

モード2(Linux 2.6以降で使用可能)では、割り当てることができる仮想アドレス空間の合計(/ proc / meminfoのCommitLimit)は次のように計算されます。

CommitLimit = (total_RAM - total_huge_TLB) * overcommit_ratio / 100 + total_swap

どこ:

  • total_RAMは、システム上のRAMの合計量です。
  • total_huge_TLBは、巨大なページ用に確保されているメモリの量です。
  • overcommit_ratioは、/ proc / sys / vm/overcommit_ratioの値です。と
  • total_swapは、スワップスペースの量です。

たとえば、16GBの物理RAM、16GBのスワップ、巨大なページ専用のスペースがなく、overcommit_ratioが50のシステムでは、この式は24GBのCommitLimitを生成します。

Linux 3.14以降、/ proc / sys / vm / overcommit_kbytesの値がゼロ以外の場合、CommitLimitは代わりに次のように計算されます。

CommitLimit = overcommit_kbytes + total_swap

/ proc / sys / vm/admiin_reserve_kbytesおよび/proc/ sys / vm/user_reserve_kbytesの説明も参照してください。

5.2.1カーネルツリーのDocumentation/vm / overcommit-accounting.rstにもいくつかの情報がありますが、少し少なくなります。

Linuxカーネルは、次のオーバーコミット処理モードをサポートしています

  • 0ヒューリスティックなオーバーコミット処理。アドレス空間の明らかなオーバーコミットは拒否されます。一般的なシステムに使用されます。オーバーコミットを許可してスワップの使用量を減らしながら、深刻なワイルドアロケーションが失敗することを保証します。このモードでは、rootはわずかに多くのメモリを割り当てることができます。これがデフォルトです。

  • 1常にオーバーコミットします。一部の科学アプリケーションに適しています。古典的な例は、スパース配列を使用し、ほぼ完全にゼロページで構成される仮想メモリに依存するコードです。

  • 2オーバーコミットしないでください。システムの合計アドレス空間コミットは、スワップ+構成可能な量(デフォルトは50%)の物理RAMを超えることはできません。使用量にもよりますが、ほとんどの場合、これはページへのアクセス中にプロセスが強制終了されないことを意味しますが、必要に応じてメモリ割り当てに関するエラーを受け取ります。

    すべてのページを初期化することなく、将来的にメモリ割り当てが利用可能になることを保証したいアプリケーションに役立ちます。

最小限の実験

最大許容値は次のように簡単に確認できます。

main.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv) {
    char *chars;
    size_t nbytes;

    /* Decide how many ints to allocate. */
    if (argc < 2) {
        nbytes = 2;
    } else {
        nbytes = strtoull(argv[1], NULL, 0);
    }

    /* Allocate the bytes. */
    chars = mmap(
        NULL,
        nbytes,
        PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS,
        -1,
        0
    );

    /* This can happen for example if we ask for too much memory. */
    if (chars == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    /* Free the allocated memory. */
    munmap(chars, nbytes);

    return EXIT_SUCCESS;
}

GitHubアップストリーム

コンパイルして実行し、1GiBと1TiBを割り当てます。

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out 0x40000000
./main.out 0x10000000000

次に、割り当て値を試して、システムで何が許可されているかを確認できます。

(デフォルト)の正確なドキュメントが見つかりません0が、32GiB RAMマシンでは、1TiBの割り当てが許可されていません。

mmap: Cannot allocate memory

ただし、無制限のオーバーコミットを有効にすると、次のようになります。

echo 1 | sudo tee /proc/sys/vm/overcommit_memory

その後、1TiBの割り当ては正常に機能します。

モード2は十分に文書化されていますが、それを検証するために正確な計算を実行するのは面倒です。しかし、実際には、次のことについて割り当てることが許可されていることを指摘しておきます。

overcommit_ratio / 100

合計RAMの、そしてデフォルトであるので、合計RAMの約半分を割り当てることができますovercommit_ratio50

VSZvsRSSおよびメモリ不足キラー

これまで、仮想メモリを割り当てました。

ただし、もちろん、ある時点で、これらのページを十分に使用すると、Linuxはいくつかのプロセスの強制終了を開始する必要があります。

Linuxのメモリ管理におけるRSSとVSZとは何ですか

于 2019-08-28T07:51:15.083 に答える
8

これを試して

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

main() {
    int Mb = 0;
    while (malloc(1<<20)) ++Mb;
    printf("Allocated %d Mb total\n", Mb);
}

そのためのstdlibとstdioを含めます。
この抽出物は、深いcの秘密から取られています。

于 2012-09-09T06:18:51.253 に答える
7

malloc独自のメモリ管理を行い、小さなメモリブロック自体を管理しますが、最終的にはWin32ヒープ関数を使用してメモリを割り当てます。あなたはmalloc「メモリ再販業者」と考えることができます。

Windowsメモリサブシステムは、物理メモリ(RAM)と仮想メモリ(HD)で構成されています。物理メモリが不足すると、一部のページを物理メモリからハードドライブの仮想メモリにコピーできます。Windowsはこれを透過的に行います。

デフォルトでは、仮想メモリは有効になっており、HDで使用可能なスペースを消費します。したがって、テストは、プロセスに全量の仮想メモリ(32ビットウィンドウでは2GB)を割り当てるか、ハードディスクがいっぱいになるまで実行を続けます。

于 2010-05-09T16:40:14.237 に答える
4

C90標準によると、32キロバイトのサイズのオブジェクトを少なくとも1つ取得できることが保証されており、これは静的、動的、または自動メモリの場合があります。C99は少なくとも64キロバイトを保証します。上限については、コンパイラのドキュメントを参照してください。

また、mallocの引数はsize_tであり、そのタイプの範囲は[0、SIZE_MAX]であるため、要求できる最大値はSIZE_MAXです。この値は実装によって異なり、で定義され<limits.h>ます。

于 2012-02-01T10:18:31.367 に答える
3

なぜ失敗したのかは実際にはわかりませんが、「malloc(4)」では実際には4バイトが得られない可能性があるため、この手法は最大ヒープサイズを見つける正確な方法ではありません。

私はここで私の質問からこれを見つけました。

たとえば、4バイトのメモリを宣言する場合、メモリの直前のスペースには、要求したメモリの量をカーネルに示すために整数4を含めることができます。

于 2010-05-09T16:38:11.747 に答える
-3

初めて*pに任意のサイズを割り当てるとき、次にそのメモリを参照されないようにするたびに。つまり、

一度にあなたのプログラムは4バイトのメモリのみを割り当てています

。では、RAM全体をどのように使用したかというと、SWAPデバイス(HDDの一時スペース)は議論の余地がありません。1つのプログラムがメモリブロックを参照していないときに、そのブロックがプログラムのメモリ要求に割り当てることができるメモリ管理アルゴリズムを知っています。それがあなたがRAMドライバに忙しくしている理由であり、それが他のプログラムにサービスを提供する機会を与えることができない理由です。また、これはぶら下がっている参照の問題です。

回答:最大でRAMサイズのメモリを割り当てることができます。スワップデバイスにアクセスできるプログラムがないためです。

あなたのすべての質問が満足のいく答えを得たことを願っています。

于 2014-07-07T13:36:39.073 に答える