0

助けてください:)OS:Linux

「sleep(1000);」のどこで、この時点で「top(Linuxタスクの表示)」は私に7.7%MEMの使用を書き込みました。valgrind:メモリリークが見つかりません。

私は理解し、正しく記述し、すべての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;
}
4

5 に答える 5

11

正当な理由により、OSにブロックを返すメモリアロケータは事実上ありません。


メモリはページ単位でのみプログラムから削除でき、それでも観察される可能性はほとんどありません。

calloc(3)およびmalloc(3)は、必要に応じて、カーネルと対話してメモリを取得します。しかし、free(3)の実装がカーネル1にメモリを返すことはほとんどありません。それらは、解放されたブロックを再利用するためにcalloc()とmalloc()が後で参照する空きリストにメモリを追加するだけです。この設計アプローチには正当な理由があります。

free()がメモリをシステムに戻したい場合でも、カーネルが実際に領域を保護するためには、少なくとも1つの連続したメモリページが必要になるため、小さなブロックを解放すると、保護が変更された場合にのみ保護が変更されます。ページの最後の小さなブロック。

動作理論

したがって、malloc(3)は、必要なときにカーネルからメモリを取得し、最終的には個別のページ倍数の単位で取得します。これらのページは、プログラムの必要に応じて分割または統合されます。Mallocとfreeは、ディレクトリを維持するために協力します。それらは、大きなブロックを提供できるようにするために、可能な場合は隣接するフリーブロックを合体させます。ディレクトリは、リンクリストを形成するために解放されたブロックのメモリを使用する場合と含まない場合があります。(代替手段は、もう少し共有メモリとページングに適しています。これには、ディレクトリ専用のメモリの割り当てが含まれます。)特別なオプションのデバッグコードがコンパイルされている場合でも、Mallocとfreeには、個々のブロックへのアクセスを強制する機能がほとんどありません。プログラム。


1. free()の実装がシステムにメモリを戻そうとすることはほとんどないという事実は、実装者が怠けているためではありません。

カーネルとの対話は、単にライブラリコードを実行するよりもはるかに遅く、メリットはわずかです。ほとんどのプログラムは定常状態または増加するメモリフットプリントを持っているため、リターナブルメモリを探すためにヒープを分析するために費やされる時間は完全に無駄になります。その他の理由としては、内部の断片化によりページ整列ブロックが存在しにくくなり、ブロックを返すとブロックがいずれかの側に断片化される可能性が高いという事実があります。最後に、大量のメモリを返すいくつかのプログラムは、malloc()をバイパスし、とにかくページを割り当てて解放する可能性があります。

于 2011-05-13T16:29:05.547 に答える
4

プログラムにメモリリークがあるかどうかを確認しようとしている場合はtop、そのジョブに適したツールではありません(valrindです)。

topOSから見たメモリ使用量を示します。を呼び出してもfree、解放されたメモリがOSに戻される保証はありません。通常、そうではありません。それでも、プロセスが後続の割り当てにメモリを使用できるという意味で、メモリは「空き」になります。

編集あなたlibcがそれをサポートしているなら、あなたはで実験することを試みることができますM_TRIM_THRESHOLD。このパスをたどったとしても、注意が必要です(ヒープの最上部近くにある単一の使用済みブロックは、その下にあるすべての空きメモリがOSに解放されるのを防ぎます)。

于 2011-05-13T15:59:56.697 に答える
2

通常、free()は物理メモリをOSに返しませんが、プロセスの仮想メモリにマップされたままです。メモリの大きなチャンクを割り当てる場合、libcはmmap()によってそれを割り当てる場合があります。次に、それを解放すると、libcはmunmap()によってメモリをOSに解放する場合があります。この場合、topはメモリ使用量が減少したことを示します。

したがって、メモリをOSに明示的に解放したくない場合は、mmap()/ munmap()を使用できます。

于 2011-05-13T16:27:13.727 に答える
1

メモリをfree()使用すると、標準Cライブラリのメモリプールに戻され、オペレーティングシステムには戻されません。オペレーティングシステムのビジョンでは、ご覧のとおりtop、プロセスはまだこのメモリを「使用」しています。プロセス内で、Cライブラリはメモリを考慮しておりmalloc()、将来的に同じポインタを返す可能性があります。

別の冒頭でもう少し説明します。

の呼び出し中にmalloc、標準ライブラリの実装により、プロセスにオペレーティングシステムから十分なメモリが割り当てられていないと判断される場合があります。そのとき、ライブラリはシステムコールを実行して、オペレーティングシステムからプロセスへのメモリをさらに受け取ります(たとえば、UnixまたはWindowsでのシステムコール)sbrk()VirtualAlloc()

ライブラリがオペレーティングシステムに追加のメモリを要求した後、ライブラリは、から戻ることができるメモリの構造にこのメモリを追加しますmalloc。後でを呼び出すとmalloc、このメモリがなくなるまで使用されます。次に、ライブラリはオペレーティングシステムにさらに多くのメモリを要求します。

メモリを使用する場合free、ライブラリは通常、メモリをオペレーティングシステムに返しません。これには多くの理由があります。理由の1つは、図書館の作者があなたがmallocもう一度電話すると信じていたからです。再度電話をかけない場合malloc、プログラムはおそらくすぐに終了します。いずれの場合も、メモリをオペレーティングシステムに戻すことにはあまり利点がありません。

ライブラリがメモリをオペレーティングシステムに返さない可能性があるもう1つの理由は、オペレーティングシステムからのメモリが大きく連続した範囲で割り当てられることです。連続する範囲全体が使用されなくなった場合にのみ返されます。呼び出しのパターンでありmallocfree使用範囲全体をクリアできない場合があります。

于 2011-05-13T16:04:15.737 に答える
0

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、ループのすべての反復で再割り当てするため、リストの最後の要素へのポインターが返されることになります。

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

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

于 2011-05-13T16:05:17.227 に答える