为什么用空函数运行std :: thread会花费大量内存

时间:2017-01-31 19:39:30

标签: c++ multithreading c++11 memory stdthread

我写了一个简单的程序,它应该运行两个线程,对小数组(~4096 Byte)进行排序并写入输出文件。输入数据包含在一个大文件中(~4Gb)。电脑有128MB内存。我发现只运行空主函数使用14MB内存。如果使用空函数应用程序运行std :: thread,则每个线程使用~8MB。但是,如果我只做一个动态内存分配程序,每个线程开始使用大约64Mb。我不明白什么可以花这么多的记忆。我该如何控制这个尺寸?如何分配动态内存以最小化某些系统默认分配?

  • 系统: Ubuntu 14.04.3
  • 编译器: gcc 4.8.4
  • 编译器选项:' -std = c ++ 11 -O3 -pthread '

  • 这是一个代码示例

    void dummy(void)
    {
        std::vector<unsigned int> g(1);
        int i = 0;
        while( i<500000000)
        {
            ++i;
        }
    }
    
    int main(void)
    {
        std::thread t1(&dummy);
        std::thread t2(&dummy);
        std::thread t3(&dummy);
        t1.join();
        t2.join();
        t3.join();
        return 0;
    }
    

2 个答案:

答案 0 :(得分:7)

每个线程都有自己的堆栈。在Linux上,默认堆栈大小为8 MB。当您第一次开始分配内存时,堆内存分配器实际上可能预先保留一个大块。这个可能解释你看到的每个线程64 MB。

那就是说,当我说“已分配”时,这并不意味着这个内存真的被使用了。分配发生在进程的虚拟内存空间中。这是您在运行VSZ时在ps列下看到的内容,或者是在您VIRT运行时top下的列RSS下看到的内容。但Linux知道你可能不会使用大部分分配的内存。因此,当您分配了一块虚拟内存时,Linux不会分配任何物理内存来备份它,直到该进程实际开始写入该内存。进程使用的实际内存量在ps REStop pthread_create()下。 Linux允许分配比总共物理内存更多的虚拟内存。

即使您的物理内存耗尽,如果32位系统上有很多线程,每个线程分配8 MB的虚拟内存,您可能会耗尽您的进程的虚拟内存空间(大约2 GB)。虽然C ++的线程库不允许您更改堆栈的大小,但C pthreads库允许您通过向pthread_attr_t提供使用pthread_attr_setstacksize()调整的Drawable myIcon = ContextCompat.getDrawable(this,R.drawable.my_vector_drawable); myIcon.setColorFilter(ContextCompat.getColor(this, R.color.yourcolor)); alertDialogBuilder.setIcon(myIcon); toolbar.setLogo(myIcon); toolbar.setNavigationIcon(myIcon); 来执行此操作。另请参阅this stackoverflow question

答案 1 :(得分:0)

您在上面的评论中为ulimit -s报告的值确实表明该线程仍然在分配堆栈,即使它是一个空主。在线程中执行的函数调用将需要一个堆栈来传递一个返回地址,假设你在x86上。

@Karrek SB正朝着正确的方向前进。您正在使用的分配器可能会影响程序的堆大小。为了避免重复调用brk或sbrk,分配器通常会请求更大的初始内存块。期望以MB为单位的值是不合理的 - 尤其是在首次初始化分配器时,沿着典型页面边界(例如4,8,32,64等)很好地对齐的值。

要控制分配的内存量,结果可能会有所不同。查看您的分配器是否支持mallopt功能。通过一些试验和错误,您可以减少总体内存占用。否则,你总是可以实现自己的分配器。