Mallocが割り当てることができる最大メモリ
-
04-10-2019 - |
質問
マシンで最大程度までどのくらいのメモリをmallocにできるかを把握しようとしていました(1 GB RAM 160 GB HD Windowsプラットフォーム)。
マロックが割り当てることができる最大メモリは、物理メモリ(ヒープ上)に制限されていることを読みました。
また、プログラムがメモリの消費を特定のレベルに超えると、他のアプリケーションが必要なメモリを十分に取得しないため、コンピューターは動作を停止します。
確認するために、私はCで小さなプログラムを書きました:
int main(){
int *p;
while(1){
p=(int *)malloc(4);
if(!p)break;
}
}
私は、メモリの割り当てが故障してループが壊れる時間があることを望んでいましたが、私のコンピューターは無限のループであるためぶら下がっています。
私は約1時間待っていたので、ついにコンピューターを強制的にシャットダウンしなければなりませんでした。
いくつかの質問:
- MallocはHDからメモリも割り当てますか?
- 上記の行動の理由は何でしたか?
- なぜループはいつでも壊れなかったのですか?
- 割り当ての失敗がなかったのはなぜですか?
解決
私はその最大メモリを読みました
malloc
割り当ては物理メモリ(ヒープ上)に制限されます。
間違っている:ほとんどのコンピューター/OSSサポート バーチャル ディスクスペースに裏打ちされたメモリ。
いくつかの質問:そうです
malloc
HDDからメモリを割り当てますか?
malloc
OSを尋ねます。これは、いくつかのディスクスペースを使用する可能性があります。
上記の行動の理由は何でしたか?なぜループがいつでも壊れなかったのですか?
割り当ての失敗がなかったのはなぜですか?
あなたは一度に少なすぎることを求めました:ループは最終的に壊れていたでしょう(仮想と物理メモリの大部分が大幅に過剰になり、結果としての超頻度のディスクアクセスがあるため、マシンがクロールに遅くなった後、「スラッシング」と呼ばれる問題")しかし、それはそれ以前にあなたの忍耐を使い果たしました。代わりに一度にメガバイトを取得してみてください。
プログラムがメモリの消費を特定のレベルに超えると、他のアプリケーションが必要なメモリを十分に取得しないため、コンピューターは動作を停止します。
完全な停止はありそうにありませんが、通常数マイクロ秒かかる操作が最終的に数十ミリ秒かかる場合、これらの4桁は確かにそれを達成する可能性があります 感じられる コンピューターが基本的に停止したかのように、通常は1分かかることがあります。
他のヒント
私はこのスレッドが古いことを知っていますが、自分で試してみたいと思っている人のために、このコードを使用してください
#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を満たします。 「怠zyな評価」を防ぐために、mallocの代わりにcallocを使用します。このスレッドから取られたアイデア:マロックメモリの質問
このコードはすぐに私のRAM(4GB)を満たし、その後約2分で20GBのスワップパーティションが死ぬ前にパーティションを交換しました。もちろん64ビットLinux。
malloc
小さなメモリブロック自体を管理する独自のメモリ管理を行いますが、最終的にはwin32を使用します ヒープ機能 メモリを割り当てる。あなたは考えることができます malloc
「メモリリセラー」として。
Windowsメモリサブシステムは、物理メモリ(RAM)と仮想メモリ(HD)で構成されています。物理メモリが不足している場合、一部のページは、ハードドライブで物理メモリから仮想メモリにコピーできます。 Windowsはこれを透過的に行います。
デフォルトでは、仮想メモリが有効になっており、HDで使用可能なスペースを消費します。したがって、テストは、プロセスの仮想メモリの全額(32ビットウィンドウで2GB)を割り当てるか、ハードディスクを埋めるまで実行され続けます。
これを試して
#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の秘密.
なぜそれが失敗したのかは実際にはわかりませんが、注意すべきことの1つは、「malloc(4)」が実際には4バイトを与えないかもしれないということです。したがって、この手法は、最大のヒープサイズを見つけるための正確な方法ではありません。
私は私の質問からこれを見つけました ここ.
たとえば、4バイトのメモリを宣言すると、メモリの直前のスペースは、整数4を含めることができます。
C90によると、サイズが少なくとも1つのオブジェクト32 kバイトを取得できることが保証されており、これは静的、動的、または自動メモリである可能性があります。 C99は少なくとも64 kバイトを保証します。上限については、コンパイラのドキュメントを参照してください。
また、Mallocの引数はsize_tであり、そのタイプの範囲は[0、size_max]です。 リクエスト is size_maxであり、値は実装によって異なり、で定義されています <limits.h>
.
/proc/sys/vm/overcommit_memory
Linuxの最大値を制御します
たとえば、ubuntu 19.04で、 それを簡単に見ることができます malloc
で実装されています mmap(MAP_ANONYMOUS
使用して strace
.
それで man proc
次に、その方法について説明します /proc/sys/vm/overcommit_memory
最大割り当てを制御します:
このファイルには、カーネル仮想メモリアカウンティングモードが含まれています。値は次のとおりです。
- 0:ヒューリスティックなオーバーコミット(これはデフォルトです)
- 1:常に交通し、チェックしないでください
- 2:常にチェックし、決して交通しないでください
モード0では、MAP_NORESERVEを使用したMMAP(2)の呼び出しはチェックされておらず、デフォルトのチェックが非常に弱く、プロセスを「ooM-cill」にするリスクにつながります。
モード1では、メモリが実際になくなるまで、カーネルは常に十分なメモリがあるふりをします。このモードのユースケースの1つは、大きなスパースアレイを採用する科学的なコンピューティングアプリケーションです。 Linuxカーネルバージョン2.6.0以前のバージョンでは、ゼロ以外の値はモード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のスワップ、巨大なページ専用のスペースがなく、50のOvercommit_ratioを備えたシステムでは、この式は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の説明も参照してください。
ドキュメント/VM/OverCommit-AcCounting.RST 5.2.1カーネルツリーもいくつかの情報を提供しますが、LOLは少し少なくなります。
Linuxカーネルは、次のオーバーコミット処理モードをサポートしています
0
ヒューリスティックな過剰積分処理。住所スペースの明らかな過剰委員会は拒否されます。典型的なシステムに使用されます。過剰なコミットがスワップの使用を削減できるようにしながら、非常にワイルドな割り当てが失敗します。ルートは、このモードでわずかに多くのメモリを割り当てることができます。これがデフォルトです。
1
常に交通してください。一部の科学的アプリケーションに適しています。古典的な例は、スパースアレイを使用したコードであり、ほぼ完全にゼロページで構成される仮想メモリに依存するだけです。
2
交付しないでください。システムのアドレススペースの合計スペースコミットは、物理RAMの設定可能な量(デフォルトは50%)を超えることは許可されていません。使用額に応じて、ほとんどの状況では、ページにアクセスする際にプロセスが殺されないが、必要に応じてメモリ割り当てのエラーを受け取ることを意味します。すべてのページを初期化することなく、メモリの割り当てを保証したいアプリケーションに役立ちます。
最小限の実験
次のような最大許容値を簡単に確認できます。
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;
}
コンパイルして実行して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
トータルラムの、そして overcommit_ratio
は 50
デフォルトでは、RAMの約半分を割り当てることができます。
VSZ VS RSSおよびMEMORY Killer
これまでのところ、仮想メモリを割り当てました。
ただし、もちろん、ある時点で、それらのページを十分に使用する場合、Linuxはいくつかのプロセスを殺す必要があります。
詳細に説明しました。 Linuxメモリ管理におけるRSSとVSZとは何ですか
初めて任意のサイズを *Pに割り当てるとき、次回はそのメモリを残すたびに、言及されていないようにします。それは意味します
一度に、プログラムは4バイトのメモリのみを割り当てています
. 。それでは、どうしてあなたがラム全体を使ったことができるのか、それが理由です スワップデバイス(HDDの一時スペース) 議論から外れています。メモリ管理アルゴリズムを知っています。これにより、メモリブロックを参照していないプログラムがない場合、そのブロックはプログラムメモリリクエストに割り当てる資格があります。だからあなたは忙しくしているだけです ラムドライバー そして、それが他のプログラムにサービスを提供する機会を与えることができない理由です。また、これはぶら下がっている参照の問題です。
ANS:ほとんどの場合、RAMサイズのメモリを割り当てることができます。スワップデバイスにアクセスできるプログラムがないためです。
あなたのすべての質問に満足のいく答えがあることを願っています。