2

システムのメモリ量をテストするACプログラムを作成しようとしています。さまざまな条件下で実行することを計画しています。

  1. スワップを有効にした場合
  2. スワップを無効にし、オーバーコミット(/ proc / sys / vm / overcommit_memory)をfalseに設定
  3. スワップを無効にし、オーバーコミット(/ proc / sys / vm / overcommit_memory)をtrueに設定
  4. システム上で実行されている仮想マシンの内部

これは、システムの実メモリと仮想メモリの制限でメモリ割り当てがどのように動作するかを知るために行っています。

私はこれを4GBのRAMと8GBのスワップを備えたマシンで実行しています。

私が現在持っているものは次のようなものです:

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

int main(void)
{
    int *ptr;
    int mb = 1048576;
    long long int i;

    for (i = 0; i < 1000000000000; i++)
    {
        printf("Trying to allocate %lld MBytes\n", i * 10 * sizeof(int) );

        ptr = (int*) calloc(10 * mb, sizeof(int));
        if ( ptr == 0 ) {
            // clean up
            free(ptr);
            printf("Ran out of memory\n");
            return 1;
        }
    }
}

私はこれが40mbのブロックを割り当て続けることを望んでいました(私のシステムではsizeof(int)は4です)。Callocはメモリをゼロに初期化します。使用可能なメモリがなくなると、プログラムが終了し、メモリが解放されます。

私がそれを実行するとき、それは私の記憶の限界を超えて実行し続けます。「5707960メガバイトを割り当てようとしています」という行を印刷しているときに、最終的に停止しました。(約6000 GBのメモリを示します。)

誰かが私がどこで間違っているのか理解できますか?

この方法で割り当てる場合は、ページファイルサイズを考慮する必要があることを指摘してくれた@BlankXavierに感謝します。

次のようにコードを変更しました。

int main(void)
{
    int *ptr;
    int mb = 1048576;
    int pg_sz = 4096;

    long long int i;

    for (i = 0; i < 1000000000000; i++)
    {
        printf("Trying to allocate %lld MBytes\n", i * pg_sz * sizeof(int) / mb );

        ptr = (int*) calloc(pg_sz, sizeof(int));
        if ( ptr == 0 ) {
            // clean up
            free(ptr);
            printf("Ran out of memory\n");
            return 1;
        }
    }
}

そして今、それは印刷を爆撃します:

「11800Mバイトを割り当てようとしています」

これは私が4GBのRAMと8GBのスワップで期待するものです。ちなみに、ディスクにスワップしているため、4GB以降は印刷速度が大幅に低下します。

4

4 に答える 4

3

まず、いくつかのアドバイス:

Cの割り当て関数からの戻り値をキャストしないでください。これにより、ある時点でほぼ確実に噛み付く特定のエラーをマスクできます(ポインターと整数の幅が異なるシステムでプロトタイプが定義されていないなど)。

割り当て関数は、他のポインターに暗黙的void *にキャストできる完全な機能を返します。

あなたの実際の質問に関しては、少なくとも特定の最適化のないシステムでは、それが失敗することを確実にするために、最前線で大規模な割り当てから始めます(a)

その場合、最初の1つが成功するまで、徐々にステップダウンします。そうすれば、ハウスキーピング情報がメモリ領域で多くのスペースを占めることや、メモリの断片化の可能性について心配する必要がありません。すぐに成功する最大の単一割り当てを見つけるだけです。

言い換えれば、次の疑似コードのようなものです。

allocsz = 1024 * 1024 * 1024
ptr = allocate_and_zero (allocsz)
if ptr != NULL:
    print "Need to up initial allocsz value from " + allocsz + "."
    exit
while ptr == NULL:
    allocsz = allocsz - 1024
    ptr = allocate_and_zero (allocsz)
print "Managed to allocate " + allocsz + " bytes."

(a)callocシステム上でスワップよりも多くのメモリを返すように見える理由については、GNU libcは特定のしきい値サイズをmmap超えると、ヒープではなく使用するため、割り当てはスワップファイルサイズに制限されません(そのバッキングストレージは他の場所にあります)。Linuxのmallocドキュメントから:

通常、malloc()はヒープからメモリを割り当て、sbrk(2)を使用して、必要に応じてヒープのサイズを調整します。MMAP_THRESHOLDバイトより大きいメモリのブロックを割り当てる場合、glibc malloc()実装は、mmap(2)を使用してメモリをプライベート匿名マッピングとして割り当てます。

これは、最初の大量の割り当てもしきい値を超えるため、上記のソリューションでは修正されない問題です。

物理メモリに関しては、すでに使用しているのでprocfs、おそらく内部を確認する必要があります/proc/meminfoMemTotal利用可能な物理メモリを提供する必要があります(そのアドレス空間の一部が他の目的で盗まれているため、完全な4Gではない可能性があります)。

仮想メモリの割り当ての場合は、割り当てサイズをしきい値未満に維持して、領域ではなくヒープから出力されるようにしますmmapmallocLinuxドキュメントからの別のスニペット:

MMAP_THRESHOLDはデフォルトで128kBですが、mallopt(3)を使用して調整可能です。

したがってmallopt、しきい値を上げるために使用するか、10Mの割り当てサイズを少し下げる(たとえば64K)かを選択します。

于 2012-08-23T09:29:53.740 に答える
3

大量の割り当てによって物理メモリを決定し、それが成功するまで割り当てサイズを減らすことはできません。

これは、利用可能な最大の仮想メモリ ブロックのサイズのみを決定します。

割り当てが失敗するまで、物理ページ サイズの (仮想ページ サイズにもなる) ブロックを割り当てて、ループする必要があります。このような単純なプログラムでは、割り当てを追跡することを心配する必要はありません。プログラムが終了すると、OS が割り当てを返します。

于 2012-08-23T09:53:29.893 に答える
0

さて、プログラムは意図したとおりに動作しますが、巨大な数にはその後にLLが必要です。そうしないと、数値を整数として扱うコンパイラによって「ランダムに」切り捨てられます。

ただし、null ポインターであるポインターを解放しても、実際には何もしません。メモリへのポインタがないため、割り当てたすべてのメモリが解放されるわけではありません。

さらに、メイン ループから抜けた場合、メインから何が返されるかは未定義です。

于 2012-08-23T09:38:31.363 に答える
-1

ループで成功した場合は、割り当てられたメモリを解放する必要があります

for (i = 0; i < 1000000000000; i++)
{
    printf("Trying to allocate %lld MBytes\n", i * 10 * sizeof(int) );

    ptr = (int*) calloc(10 * mb, sizeof(int));
    if ( ptr == 0 ) {
        printf("Ran out of memory\n");
        return 1;
    }
    else 
        free(ptr);
}
于 2012-08-23T09:35:34.530 に答える