2015-02-07 44 views
1
void * thread_client_timeout_check(void *arg) 
{ 
    pthread_attr_t attr;size_t size; 
    pthread_attr_init(&attr); 
    pthread_attr_getstacksize(&attr, &size); 
    printf("pthread stacksize: %d\n", size); 
    malloc(1); 
} 

主线程创建子线程并暂停。malloc在子线程中花费太多虚拟内存

int main() 
{ 
    pthread_t pid; 
    pthread_create(&pid, NULL, thread_client_timeout_check, NULL); 
    pause(); 
} 
  1. pthread_create之前,top virtpthread_create0.3m
  2. 后,top virt8.3m(并行线程堆栈大小是8M)
  3. malloc(1)后,top virt72.3m

为什么malloc(1)将从内核获得54m虚拟内存?

+0

并没有其他线程做任何可能增加内存的东西吗? – 2015-02-07 09:28:22

+1

如果malloc一直下到每个分配的内核,它会很慢。获得大块,然后在用户空间中处理它们更有意义。 – Mat 2015-02-07 09:48:52

+0

@ Mat你说得对,但54米太大了。我首先在主线程中检查'malloc(1)',虚拟内存仍然是0.3m。 – 2015-02-07 09:56:35

回答

4

在多线程程序中,glibc 2.10+创建了许多malloc池以减少错误共享,从而提高可伸缩性。结果是,从glibc 2.10开始,虚拟内存使用率将会更高。但是,由于地址空间很便宜,或者在64位体系结构上或多或少都是免费的,所以没什么可担心的。

https://udrepper.livejournal.com/20948.html

2

虚拟内存(virt)不是由程序分配的内存。它类似于一种内存脚印(包含数据+代码+驻留+交换内存,还包含共享库使用的共享代码和数据段)。内存分配针对不同的块大小(fastbins,mmap(),sbrk())使用不同的策略,而小的实际内存使用量可能会导致巨大的virt内存。例如。分配10次64 KiB + 1KiB块并释放较低的10 x 64KiB块。实际使用1 KiB,但堆中的内存数量为641 KiB(+ cca 100 KiB,用于最高层(所谓的荒野)块,因为堆上释放的内存仍属于进程的地址空间。

您可以使用mallinfo(3)看到实际可用内存:

#include <malloc.h> 

#define pfld(fld, unit, rem) printf(" %-9s= %d %s, (%s)\n", #fld, mi.fld, #unit, rem) 

void showmem(const char *fnc, const char *step) { 
    struct mallinfo mi = mallinfo(); 

    printf("\n==== %s: %s ====\n", fnc, step); 

    pfld(arena, bytes, "Non-mmapped space allocated"); 
    pfld(ordblks, pcs, "free chunks"); 
    pfld(smblks, pcs, "free fastbin blocks"); 
    pfld(hblks, pcs, "mmapped regions"); 
    pfld(hblkhd, bytes, "Space allocated in mmapped regions"); 
    pfld(usmblks, bytes, "Maximum total allocated space"); 
    pfld(fsmblks, bytes, "Space in freed fastbin blocks"); 
    pfld(uordblks, bytes, "Total allocated space"); 
    pfld(fordblks, bytes, "Total free space"); 
    pfld(keepcost, bytes, "Top-most, releasable space"); 
} 

从调用程序的不同部分这一功能showmem(__FUNCTION__, "Step")你可以看到总分配的空间和可用空间总量。我假设在你的情况下,总可用空间很高,总分配空间很低。这可能是由于pthread库分配和释放的内存。

您可以进行测试。使用mallopt(3)你可以要求malloc总是使用mmap(2)来分配内存不是更方便sbrk(2)。通常,mmap(2)仅用于大于或等于128 KiB的块。当内核提供的malloc'd(导致处理开销并始终分配4KiB页)时,Mmap的内存总是为零,并且在free之后总是从进程的地址空间中移除并返回给内核(所以从free'd指针读取导致分段错误)。如果mmap内存被释放,它会立即从您的地址空间中移除,因此分配的内存足迹将立即减少。试试:malloc 10 x 128 KiB + 1 KiB,然后释放10 x 128 KiB。 Virt将被减少为只包含1 KiB部分。

调用

mallopt(M_MMAP_THRESHOLD, 0); 

在程序的开始将迫使的glibc的malloc的总是使用mmap(3)。如果我的假设是真的,那么virt mem将会减少。我不建议使用它(对于小块,它会导致大量内存开销,并且总是用0来填充内存页,从而导致CPU开销),但是可以测试理论。

这只是与glibc。其他内存管理器(如tcmalloc)使用不同的策略。

我希望这有助于!

相关问题