2016-08-11 6 views
3

Учитывая это C программа, где печатается частная виртуальная память:Почему виртуальная память, выделенная с помощью malloc, не выпущена?

#include <stdio.h> 
#include <stdlib.h> 

#define _PSTAT64 
#include <sys/param.h> 
#include <sys/pstat.h> 
#include <sys/unistd.h> 

void pstatvm() 
{ 
    struct pst_vm_status pst; 
    int idx, count; 
    long long shared_vm = 0; 
    long long shared_ram = 0; 
    long long private_vm = 0; 
    long long private_ram = 0; 

    pid_t pid = getpid(); 
    idx=0; 
    count = pstat_getprocvm(&pst, sizeof(pst), (size_t)pid, idx); 
    while (count > 0) { 
    switch ((long)pst.pst_type) { 
     case PS_IO: break; 
         /* Don't count IO space. It really is not RAM or swap. */ 
     default: 
      if (pst.pst_flags & PS_SHARED) { 
       shared_vm += (long long) pst.pst_length; 
       shared_ram += (long long)pst.pst_phys_pages; 
      } else { 
       private_vm += (long long) pst.pst_length; 
       private_ram += (long long)pst.pst_phys_pages; 
      } 
        break; 
    } 

    idx++; 
    count = pstat_getprocvm(&pst, sizeof(pst), (size_t)pid, idx); 
    } 
    printf("%d\t\t", pid); 
    printf("%lldK\t\t", shared_vm*4); 
    printf("%lldK\t\t", shared_ram*4); 
    printf("%lldK\t\t", private_vm*4); 
    printf("%lldK\n", private_ram*4); 
} 



int main() 
{ 
    void *p=NULL; 
    int cont = 1; 

    printf("pid\t\tshared_vm\tshared_ram\tprivate_vm\tprivate_ram\n"); 

    while(cont < 100) 
    { 
     p = malloc((cont*10)*1024*1024); 
     if (p == NULL) 
     { 
      printf("exit\n"); 
      exit(1); 
     } 
     pstatvm(); 
     free(p); p=NULL; 
     sleep(1); 
     cont += 10; 
    } 

    printf ("\n\n"); 
    cont = 0; 
    while(cont < 10) 
    { 
     sleep(100); 
     pstatvm(); 
     ++cont; 
    } 

} 

Почему private_vm не освобожден от ОС?

pid    shared_vm  shared_ram  private_vm  private_ram 
8988   3436K   2432K   26880K   320K 
8988   3436K   2432K   129280K   336K 
8988   3436K   2432K   231680K   352K 
8988   3436K   2432K   334080K   368K 
8988   3436K   2432K   436480K   384K 
8988   3436K   2432K   538880K   400K 
8988   3436K   2432K   641280K   416K 
8988   3436K   2432K   743680K   432K 
8988   3436K   2432K   846080K   448K 
8988   3436K   2432K   948480K   464K 


8988   3436K   2432K   948480K   464K 
8988   3436K   2432K   948480K   464K 
8988   3436K   2432K   948480K   464K 
8988   3436K   2432K   948480K   464K 
8988   3436K   2432K   948480K   464K 
8988   3436K   2432K   948480K   464K 
8988   3436K   2432K   948480K   464K 
8988   3436K   2432K   948480K   464K 
8988   3436K   2432K   948480K   464K 
8988   3436K   2432K   948480K   464K 

От http://www.linuxforums.org/forum/programming-scripting/153369-solved-where-does-memory-allocated-malloc-actually-come.html:

В Linux/Unix, вся память приложения является виртуальным, и если она не выгружена на диск он указывает на место в физической памяти. Каждая страница может быть отдельно рассмотрена, поэтому в то время как приложение куча (памяти, выделенная с таНосом)() появляется в приложение как смежные, он на самом деле может быть распространен по всему вашей физической памяти

+1

«если он не поменяется на диск, он указывает на место в физической памяти» - не совсем верно. Он также может быть не привязан к чему-либо. –

+0

Жозе, можете ли вы публиковать журнал системных вызовов из основного цикла ('while'), например, он напечатан в linux strace или в freebsd фермой (tusc in hpux http://knowledgebase.progress.com/articles/Article/3669)? Malloc такого размера может использовать либо brk/sbrk для реальной кучи, либо mmap; mmap проще разблокировать, чем фрагментированную кучу (какова ваша реализация libc?). Можете ли вы также переместить 'pstatvm();' от внутреннего цикла while до точки после цикла (printf/pstat может иметь свои собственные вызовы в malloc, что предотвращает повторное использование/фрагменты пространства кучи)? Какая версия hpux и libc? – osgx

+0

Без знания используемых функций/типов: похоже, слишком много отливок. Никогда не используйте ненужный бросок. Сначала скомпилируйте, а затем добавьте, если вы действительно знаете, что делаете. – Olaf

ответ

3

malloc() и free() не обязаны для выделения/освобождения виртуальной памяти. Они справляются с кучей. И независимо от того, что malloc() использует sbrk() для увеличения кучи при необходимости, free() не сжимает кучу назад, поэтому объем выделенной виртуальной памяти остается таким же, как сразу после malloc().

4

Если вы хотите выделить большую область памяти, так что они не будут действительно освобождены, когда приложение больше не нуждается в них, а затем использовать POSIX mmap и munmap функции непосредственно, а не полагаться на поведении, которое достаточно большие malloc запросов переводятся до mmap.

Возможно, GNU C Library работает в GNU/Linux, но это не стандартизованное требование, и поэтому ожидание не переносится.

Очевидно, что ваша система HP-UX malloc сохраняет базовое хранилище даже больших распределений. Однако обратите внимание, как приращения размера виртуальной машины составляют около 100 МБ. Это показывает, что распределитель повторно использует ранее освобожденную память, избегая фрагментации. То есть, когда вы освобождаете блок 300 Мб, а затем выделяете 400 Мб, он не сохраняет исходный 300 Мб, а затем выделяет совершенно новый блок 400 Мб; он понимает, что пространство в 300 Мб, которое ранее было освобождено, можно просто расширить. В распределителе могут быть дополнительные скрытые стратегии, которые не демонстрируют шаблон распределения вашей программы. Все, что мы знаем из вашей программы, состоит в том, что когда мы делаем одно большое выделение, а затем освобождаем его, распределитель может поддерживать его и расширять, чтобы удовлетворить еще больший запрос на распределение. Это не доказывает, что распределитель всегда хранит большие освобожденные ассигнования; это может быть оптимизация только для этого случая (возможно, для поддержки повторения realloc).