Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.
Announcements
The Intel sign-in experience has changed to support enhanced security controls. If you sign in, click here for more information.

memory leak from parallel for?

rnickb
Beginner
1,007 Views

Clang's address sanitizer detects a memory leak in TBB when this program is run

#include <tbb/parallel_for.h>                                                    
#include <vector>                                                                
#include <cmath>                                                                 
                                                                                 
template <class T>                                                               
void do_not_optimize_away(T&& x) {                                               
  asm volatile("" : "+r"(x));                                                    
}                                                                                
                                                                                 
const int N = 100'000;                                                           
void f() {                                                                       
  std::vector<double> v(N);                                                      
  for (int i = 0; i < N; ++i) v = std::sqrt(i);                               
  do_not_optimize_away(v.data());                                                
}                                                                                
                                                                                 
int main() {                                                                     
  tbb::parallel_for(0, 100, [](int i) { f(); });                                 
  return 0;                                                                      
} 

The report I get is

=================================================================
==17071==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 3096 byte(s) in 3 object(s) allocated from:
    #0 0x4cb25b in operator new[](unsigned long) /root/clang-march30_15/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:64:37
    #1 0x7f14f5649e12 in tbb::internal::task_stream<3>::initialize(unsigned int) /root/tbb/tbb44_20150728oss/build/linux_intel64_gcc_cc4.7.3_libc2.17_kernel3.10.25_debug/../../src/tbb/task_stream.h:94
    #2 0x7f14f56462f3 in tbb::internal::arena::arena(tbb::internal::market&, unsigned int) /root/tbb/tbb44_20150728oss/build/linux_intel64_gcc_cc4.7.3_libc2.17_kernel3.10.25_debug/../../src/tbb/arena.cpp:185
    #3 0x7f14f5646436 in tbb::internal::arena::allocate_arena(tbb::internal::market&, unsigned int) /root/tbb/tbb44_20150728oss/build/linux_intel64_gcc_cc4.7.3_libc2.17_kernel3.10.25_debug/../../src/tbb/arena.cpp:201
    #4 0x7f14f5642eab in tbb::internal::market::create_arena(int, unsigned long, bool) /root/tbb/tbb44_20150728oss/build/linux_intel64_gcc_cc4.7.3_libc2.17_kernel3.10.25_debug/../../src/tbb/market.cpp:234
    #5 0x7f14f56417d2 in tbb::internal::governor::init_scheduler(int, unsigned long, bool) /root/tbb/tbb44_20150728oss/build/linux_intel64_gcc_cc4.7.3_libc2.17_kernel3.10.25_debug/../../src/tbb/governor.cpp:193
    #6 0x7f14f563eac7 in tbb::internal::governor::local_scheduler() /root/tbb/tbb44_20150728oss/build/linux_intel64_gcc_cc4.7.3_libc2.17_kernel3.10.25_debug/../../src/tbb/governor.h:133
    #7 0x7f14f563e380 in tbb::internal::get_initial_auto_partitioner_divisor() /root/tbb/tbb44_20150728oss/build/linux_intel64_gcc_cc4.7.3_libc2.17_kernel3.10.25_debug/../../src/tbb/task.cpp:157
    #8 0x4d1d11 in tbb::interface7::internal::adaptive_partition_type_base<tbb::interface7::internal::auto_partition_type>::adaptive_partition_type_base() (/home/rnburn/bugs/tbb_leak/a.out+0x4d1d11)
    #9 0x4d1c1f in tbb::interface7::internal::auto_partition_type::auto_partition_type(tbb::auto_partitioner const&) (/home/rnburn/bugs/tbb_leak/a.out+0x4d1c1f)
    #10 0x4ccdc1 in tbb::interface7::internal::start_for<tbb::blocked_range<int>, tbb::internal::parallel_for_body<main::$_0, int>, tbb::auto_partitioner const>::start_for(tbb::blocked_range<int> const&, tbb::internal::parallel_for_body<main::$_0, int> const&, tbb::auto_partitioner const&) (/home/rnburn/bugs/tbb_leak/a.out+0x4ccdc1)
    #11 0x4ccc18 in tbb::interface7::internal::start_for<tbb::blocked_range<int>, tbb::internal::parallel_for_body<main::$_0, int>, tbb::auto_partitioner const>::run(tbb::blocked_range<int> const&, tbb::internal::parallel_for_body<main::$_0, int> const&, tbb::auto_partitioner const&) (/home/rnburn/bugs/tbb_leak/a.out+0x4ccc18)
    #12 0x4cca24 in void tbb::parallel_for<tbb::blocked_range<int>, tbb::internal::parallel_for_body<main::$_0, int> >(tbb::blocked_range<int> const&, tbb::internal::parallel_for_body<main::$_0, int> const&, tbb::auto_partitioner const&) (/home/rnburn/bugs/tbb_leak/a.out+0x4cca24)
    #13 0x4cc7d8 in void tbb::strict_ppl::parallel_for_impl<int, main::$_0, tbb::auto_partitioner const>(int, int, int, main::$_0 const&, tbb::auto_partitioner const&) (/home/rnburn/bugs/tbb_leak/a.out+0x4cc7d8)
    #14 0x4cc405 in void tbb::strict_ppl::parallel_for<int, main::$_0>(int, int, main::$_0 const&) (/home/rnburn/bugs/tbb_leak/a.out+0x4cc405)
    #15 0x4cc291 in main (/home/rnburn/bugs/tbb_leak/a.out+0x4cc291)
    #16 0x7f14f474db94 in __libc_start_main (/lib64/libc.so.6+0x24b94)

SUMMARY: AddressSanitizer: 3096 byte(s) leaked in 3 allocation(s).

When I compiled with

clang++ -std=c++14 -fsanitize=address -ltbb_debug main.cpp

using clang 3.6

False positives with address sanitizer should be very rare (http://clang.llvm.org/docs/AddressSanitizer.html). And I tried adding some print statements and it looks like the destructor for task_stream may not have been called.

0 Kudos
8 Replies
RafSchietekat
Black Belt
1,008 Views

What happens if you put an explicit "tbb::task_scheduler_init anonymous;" just before the call to parallel_for()?

rnickb
Beginner
1,008 Views

there's no reported memory leak with "tbb::task_scheduler_init anonymous;"

Vladimir_P_1234567890
1,008 Views

rnickb wrote:

there's no reported memory leak with "tbb::task_scheduler_init anonymous;"

That means that if you use scoped initialization, all odjects are destroyed in the end of the scope. If you use autoinitialization (without tbb::task_scheduler_init) then created objects live till the end of the program. So it looks that everything works correctly

--Vladimir

rnickb
Beginner
1,008 Views

Can't they be deleted at the end of the program so that it doesn't flag as a memory leak?

Vladimir_P_1234567890
1,008 Views

Yes they can. You just need to construst this object and destruct it like it is done for other C++ objects.

rnickb
Beginner
1,008 Views

Why can't the library guarantee the destructors are called, irrespective of whether task_scheduler_init object is created or not so that all the allocated heap memory gets cleanly deleted?

Vladimir_P_1234567890
1,008 Views

Upon exit OS kills worker threads where destructors are located so it is impossible to call destructors in this case. if you use C++ style for creating/deleting objects then destructors are called.

If lazy (auto) initialization is used I do not see any issues with fact that lazy de-initialization is used. And de-initialization is so lazy that it is done by an operating system.:)

--Vladimir

Roman_P_Intel
Employee
1,008 Views

task_scheduler_init has been deprecated. What is the current BKM to use TBB with ASAN?

Reply