2017-03-03 120 views
1

重新使用使用英特尔TBB功能的线程时,我们遇到高内存开销。我们预计一旦某个线程完成了给定的工作负载,就会释放相应的内存。但是,这似乎并不是这种情况,即使线程执行工作单元之间有很长时间的停顿。英特尔tbb内存开销

我们准备了一个例子来说明这个问题:

int main() { 
    blocking_queue<size_t> command_input_queue; 
    tbb::atomic<size_t> count = 1; 
    //workers 
    std::vector<std::thread> worker; 
    for(size_t i = 0; i < 15; i++) { 
     worker.push_back(std::thread([&command_input_queue, &count](){ 
     while(true) 
     { 
      size_t size; 
      //wait for work.. 
      command_input_queue.wait_and_pop(size); 
      //do some work with Intel TBB 
      std::vector<int32_t> result(size); 
      for(size_t i = 0; i < result.size(); i++) { 
       result[i] = i % 1000; 
      } 
      tbb::parallel_sort(result.begin(), result.end()); 
      size_t local_count = count++; 
      std::cout << local_count << " work items executed " << std::endl; 
     } 
    })); 
    } 
    //enqueue work 
    size_t work_items = 15; 
    for(size_t i = 0; i < work_items ; i++) { 
     command_input_queue.push(10 * 1000 * 1000); 
    } 

    while(true) { 
     boost::this_thread::sleep(boost::posix_time::seconds(1)); 
     if(count > 15) { 
     break; 
     } 
    } 
    //wait for more commands 
    std::cout << "Wait" << std::endl; 
    boost::this_thread::sleep(boost::posix_time::seconds(60)); 

    //----!During the wait, while no thread is active, 
    //the process still claims over 500 MB of memory!---- 
    for(size_t i = 0; i < 15; i++) { 
    command_input_queue.push(1000 * 1000); 
    } 
... 

在这个例子中,我们开始15个工作线程。他们等待任务并执行tbb :: parallel_sort并在完成后释放所有资源。 问题是所有任务都处理完毕,所有工作人员都在等待新的任务,这个过程仍然声称有500MB的内存。

像valgrind的地块这样的工具没有告诉我们内存在哪里。 我们将程序与libtbb.so链接起来。所以tbb分配器不应该成为问题。

有人知道我们如何释放内存,而工人闲置吗?

+0

我把你的测试修改了一下(用tbb :: concurrent_bounded_queue代替blocking_queue,用std :: this_thread :: sleep_for代替boost :: this_thread_sleep),并用Visual Studio 2015和Intel TBB 2017 Update 2编译。最终的测试在峰值时使用了〜500MB,但是当主线程开始等待时,快速降低到〜1.7MB--即问题未被复制。 –

+0

感谢您付出努力尝试重现此问题。我在TBB 2017上也在Ubuntu 14.04上进行了测试。 在我的系统上,即使运行修改后的测试,内存消耗也没有完成。但是在调用'malloc_trim'(见下面的答案)之后,它会下降到〜2MB。所以它似乎是依赖于系统的。 –

回答

2

在拨打deletefree后,堆分配的内存通常不会返回到操作系统。您需要拨打malloc_trim或您的分配程序特定功能来执行此操作。

+0

谢谢!这解决了这个问题。在等待之前调用'malloc_trim'将内存消耗减少到〜2MB。 –

2

TBB调度程序缓存任务分配,尽管连接分配器,尽管它没有解释500MB。可以解释的是,TBB动态加载TBB分配器,当然,它可以在libtbb.so旁边找到内存。您可以通过设置env来检查tbbmalloc是否被激活var TBB_VERSION=1

我觉得很奇怪的是,为什么TBB创建自己的工作人员时超时订阅机器与工作线程?

+0

你说得对,我们在这个例子中超额订阅。这个例子只是一个复杂系统的简化提取。因此,我不能简单地改变这一部分的实施。 –