質問

助けてください:) 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_dbmake_cache_db()を割り当てている方法はバグのようです。あなたの意図はリンクリストリストの最初の要素へのポインタを返すことです。しかし、ループの反復ごとにcache_dbを再割り当てしているため、リストの last 要素へのポインタを返すことになります。

    後でfree_cache_db()を使用してリストを解放すると、メモリがリークされます。ただし、現時点では、この問題は前の箇条書きで説明されているバグによってマスクされ、長さ1のリストが割り当てられます。

    これらのバグとは無関係に、AIXによって発生したポイントは非常に有効です。ランタイムライブラリは、すべてのfree()dメモリをオペレーティングシステムに返す必要はありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top