質問
助けてください:) OS:Linux
「 sleep(1000); 」のところに、このとき「top (Linux タスクの表示)」は 7.7 %MEM 使用と書いてあります。ヴァルグリンド :メモリリークが見つかりませんでした。
理解しており、正しく記述しましたが、malloc の結果はすべて NULL です。しかし、今回はなぜ私のプログラムが「スリープ」してもメモリが減らないのでしょうか?何が欠けているのですか?
下手な英語でごめんなさい、ありがとう
~ # tmp_soft
For : Is it free?? no
Is it free?? yes
For 0
For : Is it free?? no
Is it free?? yes
For 1
END : Is it free?? yes
END
~ #top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
23060 root 20 0 155m 153m 448 S 0 7.7 0:01.07 tmp_soft
完全なソース:tmp_soft.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
struct cache_db_s
{
int table_update;
struct cache_db_s * p_next;
};
void free_cache_db (struct cache_db_s ** cache_db)
{
struct cache_db_s * cache_db_t;
while (*cache_db != NULL)
{
cache_db_t = *cache_db;
*cache_db = (*cache_db)->p_next;
free(cache_db_t);
cache_db_t = NULL;
}
printf("Is it free?? %s\n",*cache_db==NULL?"yes":"no");
}
void make_cache_db (struct cache_db_s ** cache_db)
{
struct cache_db_s * cache_db_t = NULL;
int n = 10000000;
for (int i=0; i = n; i++)
{
if ((cache_db_t=malloc(sizeof(struct cache_db_s)))==NULL) {
printf("Error : malloc 1 -> cache_db_s (no free memory) \n");
break;
}
memset(cache_db_t, 0, sizeof(struct cache_db_s));
cache_db_t->table_update = 1; // tmp
cache_db_t->p_next = *cache_db;
*cache_db = cache_db_t;
cache_db_t = NULL;
}
}
int main(int argc, char **argv)
{
struct cache_db_s * cache_db = NULL;
for (int ii=0; ii 2; ii++) {
make_cache_db(&cache_db);
printf("For : Is it free?? %s\n",cache_db==NULL?"yes":"no");
free_cache_db(&cache_db);
printf("For %d \n", ii);
}
printf("END : Is it free?? %s\n",cache_db==NULL?"yes":"no");
printf("END \n");
sleep(1000);
return 0;
}
解決
プログラムがメモリリークがあるかどうかを確立しようとしている場合、top
はジョブの正しいツールではありません(valrind
は)
top
OSから見たメモリ使用量を表示します。free
を呼び出しても、解放メモリがOSに返されることを保証することはありません。通常はそうではありません。それにもかかわらず、メモリはあなたのプロセスがその後の割り当てのためにそれを使用できるという意味で「無料」になります。
編集あなたのlibc
がそれをサポートしている場合は、 M_TRIM_THRESHOLD
。あなたがこの道をたどったとしても、それは難しいことになるでしょう(ヒープの上部に近い単一の中古ブロックは、それ以降のすべての無料のメモリがOSにリリースされるのを防ぎます)。
他のヒント
良い理由で、メモリ割り当て者は事実上、OS にブロックを返しません。
メモリは、ページ単位でプログラムからのみ取り除くことができます。
calloc(3)とmalloc(3)は、必要に応じてメモリを取得するためにカーネルと対話します。しかし、それほど無料の(3)の実装は、カーネル 1 への返信メモリを返します。ブロックを解放しました。この設計アプローチのための良い理由があります。
システムにメモリを返すようにしたい場合でも、カーネルを実際に保護するために少なくとも1つの連続したメモリページが必要であろうので、小ブロックをリリースすることは保護変化のみをリリースするであろうページ内の last 小ブロックであれば。
操作体理論
so malloc(3)カーネルからメモリを取得すると、最終的にはディスクリートページ倍数の単位です。これらのページは、プログラムが必要とするために分割または統合されています。 Mallocと無料ディレクトリを維持するために協力します。大きなブロックを提供できるようにするために可能な場合、それらは可能な限り隣接する自由ブロックを合体する。ディレクトリは、リードブロック内のメモリを使用してリンクされたリストを形成することができない場合があります。 (代わりはもう少しシェアードメモリとページングフレンドリングで、特にディレクトリに特に割り当てることを含みます。)MallocとFreeは、特別なデバッグコードがコンパイルされていても個々のブロックへのアクセスを強制する機能がほとんどありません。プログラム
1。システムにメモリを返すためのrefe()の実装はほとんどないという事実は、実装者がオフの弛みを遅らせるためにまったくありません。
カーネルとの対話はより遅くなります。単にライブラリコードを実行し、その利点は小さくなります。ほとんどのプログラムは定常状態または上昇したメモリフットプリントを持っているので、返信可能なメモリを探しているヒープの分析に費やされた時間は完全に無駄になります。その他の理由には、内部フラグメンテーションがページ整合ブロックが存在しないことをほとんどないという事実を含み、ブロックを返す可能性が高いため、ブロックをどちら側にフラグメント化することもできます。最後に、大量のメモリを返すいくつかのプログラムは、Malloc()をバイパスし、単にページと無料のページと無料のページを配置する可能性があります。
一般的な()はOSに物理メモリを返さないため、プロセスの仮想メモリにまだマッピングされています。大きなメモリを割り当てると、libcはmmap()によって割り当てられます。それから、あなたがそれを解放した場合、libcはmunmap()によってメモリをOSに解放するかもしれません。
だから、OSにメモリを明示的に解放している場合は、mmap()/ munmap()を使用できます。
あなたが free()
メモリに返されると、標準 C ライブラリのメモリ プールに返され、オペレーティング システムには返されません。オペレーティング システムのビジョンを通して見ると、 top
, 、プロセスはまだこのメモリを「使用」しています。プロセス内では、C ライブラリがメモリを割り当てており、C ライブラリから同じポインタを返す可能性があります。 malloc()
将来。
別の冒頭でもう少し説明します。
通話中 malloc
, の場合、標準ライブラリ実装は、プロセスにオペレーティング システムから十分なメモリが割り当てられていないと判断する場合があります。このとき、ライブラリはシステム コールを実行して、オペレーティング システムからプロセスにさらに多くのメモリを受け取ります (たとえば、 sbrk()
または VirtualAlloc()
それぞれ Unix または Windows のシステム コール)。
ライブラリは、オペレーティング システムに追加のメモリを要求した後、このメモリを、オペレーティング システムから返すことができるメモリの構造に追加します。 malloc
. 。その後の電話 malloc
このメモリは使い果たされるまで使用されます。次に、ライブラリはオペレーティング システムにさらに多くのメモリを要求します。
あなたが free
通常、ライブラリはメモリをオペレーティング システムに返しません。これには多くの理由があります。理由の 1 つは、ライブラリの作成者が、あなたが電話をかけるだろうと信じていたことです。 malloc
また。電話をかけない場合は malloc
繰り返しますが、あなたのプログラムはおそらくすぐに終了します。いずれの場合も、メモリをオペレーティング システムに戻すメリットはあまりありません。
ライブラリがオペレーティング システムにメモリを返さないもう 1 つの理由は、オペレーティング システムからのメモリが大きな連続した範囲に割り当てられていることです。これは、連続した範囲全体が使用されなくなった場合にのみ返されます。電話をかけるパターン malloc
そして free
使用範囲全体をクリアできない場合があります。
2つの問題点:
-
make_cache_db()
、行
.for (int i=0; i = n; i++)
おそらくを読むべきです
.for (int i=0; i<n; i++)
それ以外の場合は、単一の
cache_db_s
ノードのみを割り当てます。 -
cache_db
にmake_cache_db()
を割り当てている方法はバグのようです。あなたの意図はリンクリストリストの最初の要素へのポインタを返すことです。しかし、ループの反復ごとにcache_db
を再割り当てしているため、リストの last 要素へのポインタを返すことになります。後で
free_cache_db()
を使用してリストを解放すると、メモリがリークされます。ただし、現時点では、この問題は前の箇条書きで説明されているバグによってマスクされ、長さ1のリストが割り当てられます。これらのバグとは無関係に、AIXによって発生したポイントは非常に有効です。ランタイムライブラリは、すべての
free()
dメモリをオペレーティングシステムに返す必要はありません。