簡體   English   中英

C中的問題用法存儲器

[英]Problem usage memory in C

請幫助:)操作系統: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;
}

出於充分的原因,幾乎沒有內存分配器將塊返回給操作系統


只能以頁為單位從程序中刪除內存,即使這樣也不太可能觀察到。

如果需要,calloc(3)和malloc(3)會與內核進行交互以獲取內存。 但是,很少有free(3)的實現曾經將內存返回內核1 ,他們只是將其添加到一個空閑列表中,calloc()和malloc()稍后將查詢該列表以重用釋放的塊。 這種設計方法有充分的理由。

即使free()想要將內存返回給系統,它也至少需要一個連續的內存頁才能使內核實際保護該區域,因此釋放一個小塊只會導致保護更改,如果它是頁面中的最后一個小塊。

操作理論

因此,malloc(3)在需要時從內核獲取內存,最終以離散頁面倍數為單位。 這些頁面根據程序要求進行划分或合並。 Malloc和free合作維護一個目錄。 它們盡可能合並相鄰的空閑塊,以便能夠提供大塊。 該目錄可能涉及也可能不涉及在釋放的塊中使用內存以形成鏈接列表。 (另一種選擇是共享內存和分頁更友好,並且它涉及專門為目錄分配內存。)即使將特殊和可選的調試代碼編譯到其中,Malloc和free幾乎也沒有能力強制訪問各個塊。該程序。


1.很少有free()的實現嘗試將內存返回給系統的事實完全不是由於實現者的懈怠。

與內核進行交互比僅執行庫代碼要慢得多,並且好處很小。 大多數程序具有穩定狀態或增加的內存占用量,因此用於尋找可返回內存的分析堆所花費的時間將完全浪費。 其他原因包括內部碎片使頁面對齊的塊不太可能存在的事實,並且返回一個塊可能會將塊碎片分散到任一側。 最后,少數返回大量內存的程序可能會繞過malloc(),並且無論如何都只是分配和釋放頁面。

如果您要確定程序是否存在內存泄漏,那么top並不是適合該工作的工具( valrind是)。

top顯示了操作系統看到的內存使用情況。 即使您調用free ,也無法保證釋放的內存將返回給OS。 通常情況下不會。 但是,在您的進程可以將其用於后續分配的意義上,內存確實變得“空閑”。

編輯如果您的libc支持它,則可以嘗試使用M_TRIM_THRESHOLD 即使您遵循此路徑,也將非常棘手(靠近堆頂部的單個使用過的塊將阻止將其下的所有可用內存釋放給操作系統)。

通常,free()不會將物理內存退還給OS,它們仍映射在您進程的虛擬內存中。 如果您分配了很大的內存,libc可以通過mmap()分配它; 那么如果您釋放它,libc可能會通過munmap()將內存釋放到OS,在這種情況下,top將顯示您的內存使用量下降。

因此,如果不想將內存顯式釋放到OS,則可以使用mmap()/ munmap()。

當您free()內存時,它將返回到標准C庫的內存池,而不返回到操作系統。 在操作系統的視野中,正如您從top看到的那樣,該過程仍在“使用”此內存。 在此過程中,C庫占用了內存,將來可能會從malloc()返回相同的指針。

我將以不同的開頭進一步解釋它:

在調用malloc期間,標准庫實現可能會確定該進程沒有從操作系統分配足夠的內存。 屆時,該庫將進行系統調用以從操作系統接收更多的內存給進程(例如,分別在Unix或Windows上執行sbrk()VirtualAlloc()系統調用)。

庫從操作系統請求其他內存后,它將將此內存添加到可從malloc返回的內存結構中。 以后對malloc調用將使用此內存,直到用完為止。 然后,庫要求操作系統提供更多的內存。

free內存時,庫通常不會將內存返回給操作系統。 這件事情是由很多原因導致的。 原因之一是庫作者認為您將再次調用malloc 如果您不再調用malloc ,則程序可能很快就會結束。 無論哪種情況,將內存返回到操作系統都沒有太多優勢。

庫可能不會將內存返回給操作系統的另一個原因是,來自操作系統的內存分配在較大的連續范圍內。 僅當不再使用整個連續范圍時才可以返回它。 調用mallocfree的模式可能無法清除整個使用范圍。

兩個問題:

  • make_cache_db() ,該行

     for (int i=0; i = n; i++) 

    應該讀

     for (int i=0; i<n; i++) 

    否則,您將只分配一個cache_db_s節點。

  • make_cache_db()分配cache_db的方式似乎有問題。 看來您的意圖是返回一個指向鏈表第一個元素的指針; 但是由於在循環的每次迭代中都要重新分配cache_db ,所以最終將返回一個指向列表最后一個元素的指針。

    如果以后使用free_cache_db()釋放列表,這將導致您泄漏內存。 但是,目前,此問題已由上一個項目符號點中描述的錯誤掩蓋,該錯誤使您只能分配長度為1的列表。

與這些錯誤無關,aix提出的觀點非常有效:運行時庫無需將所有free() d內存返回給操作系統。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM