子线程中的malloc花费太多虚拟内存

时间:2015-02-07 09:20:49

标签: c linux multithreading glibc

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);
}

主线程创建子项并暂停。

int main()
{
    pthread_t pid;
    pthread_create(&pid, NULL, thread_client_timeout_check, NULL);
    pause();
}
  1. pthread_create之前,top virt0.3m
  2. pthread_create之后,top virt8.3m(pthread堆栈大小为8米)
  3. malloc(1)之后,top virt72.3m
  4. 为什么malloc(1)将从内核获得54m虚拟内存?

2 个答案:

答案 0 :(得分:4)

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

请参阅https://udrepper.livejournal.com/20948.html

答案 1 :(得分:2)

虚拟内存(virt)不是程序分配的内存。非常类似于一种内存脚印(包含数据+代码+驻留+交换内存。它还包含共享库使用的共享代码和数据段)。 Glibc的 malloc内存分配对不同的块大小使用不同的策略(fastbins,mmap(),sbrk()),小的实际内存使用量会导致巨大的内存。例如。分配10倍64 KiB + 1KiB块并释放较低的10 x 64KiB块。实际使用量为1 KiB,但在virt中计算的堆内存为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'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)使用不同的策略。

我希望这有帮助!

相关问题