你好
我准备在项目中引入你的boost memory 2.20 但刚开始测试就发现一些问题,我的环境是linux 内核 2.6.10 +gcc 4.1
首先是编译错误 boost/memory/memory.hpp
inline void winx_call swap(void* a, void* b, size_t cb)
{
void* t = _alloca(cb);
memcpy(t, a, cb);
memcpy(a, b, cb);
memcpy(b, t, cb);
}
template <class Type>
void winx_call swap_object(Type* a, Type* b) {
swap(a, b, sizeof(Type));
}
只有把winx_call和_alloca 去掉才可以:
inline void swap(void* a, void* b, size_t cb)
{
void* t = alloca(cb);
memcpy(t, a, cb);
memcpy(a, b, cb);
memcpy(b, t, cb);
}
template <class Type>
void swap_object(Type* a, Type* b) {
swap(a, b, sizeof(Type));
}
其次,我使用了你提供的stl_containers.cpp进行测试,但用valgrind发觉很大内存漏洞:
==9386== Memcheck, a memory error detector.
==9386== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==9386== Using LibVEX rev 1732, a library for dynamic binary translation.
==9386== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==9386== Using valgrind-3.2.3, a dynamic binary instrumentation framework.
==9386== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==9386== For more details, rerun with: -v
==9386==
===== Deque (scoped_alloc) =====
===== List (scoped_alloc) =====
===== Set (scoped_alloc) =====
===== Map (scoped_alloc) =====
==9386==
==9386== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 5 from 1)
==9386== malloc/free: in use at exit: 10,890,496 bytes in 670 blocks.
==9386== malloc/free: 670 allocs, 0 frees, 10,890,496 bytes allocated.
==9386== For counts of detected errors, rerun with: -v
==9386== searching for pointers to 670 not-freed blocks.
==9386== checked 3,393,752 bytes.
==9386==
==9386== 16 bytes in 1 blocks are definitely lost in loss record 1 of 7
==9386== at 0x4A06205: operator new(unsigned long) (vg_replace_malloc.c:167)
==9386== by 0x400FC1: testMap() (tls.hpp:137)
==9386== by 0x401A68: main (test.cc:92)
==9386==
==9386==
==9386== 441,520 (16 direct, 441,504 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 7
==9386== at 0x4A06205: operator new(unsigned long) (vg_replace_malloc.c:167)
==9386== by 0x40196A: testDeque() (tls.hpp:137)
==9386== by 0x401A48: testStlContainers() (test.cc:84)
==9386== by 0x401A68: main (test.cc:92)
==9386==
==9386==
==9386== 2,403,760 (16 direct, 2,403,744 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 7
==9386== at 0x4A06205: operator new(unsigned long) (vg_replace_malloc.c:167)
==9386== by 0x4016CC: testList() (tls.hpp:137)
==9386== by 0x401A4D: testStlContainers() (test.cc:85)
==9386== by 0x401A68: main (test.cc:92)
==9386==
==9386==
==9386== 4,022,608 (16 direct, 4,022,592 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 7
==9386== at 0x4A06205: operator new(unsigned long) (vg_replace_malloc.c:167)
==9386== by 0x4011D0: testSet() (tls.hpp:137)
==9386== by 0x401A52: testStlContainers() (test.cc:86)
==9386== by 0x401A68: main (test.cc:92)
==9386==
==9386==
==9386== 16,352 bytes in 1 blocks are possibly lost in loss record 5 of 7
==9386== at 0x4A059F6: malloc (vg_replace_malloc.c:149)
==9386== by 0x4C09F88: boost::memory::stdlib_alloc::allocate(unsigned long) (system_alloc.hpp:67)
==9386== by 0x4C0A033: boost::memory::system_pool_imp<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:141)
==9386== by 0x4C0A059: boost::memory::system_pool_s<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:181)
==9386== by 0x4C09BE0: _boost_SystemPoolAlloc (system_pool.cpp:24)
==9386== by 0x400FF3: testMap() (system_alloc.hpp:139)
==9386== by 0x401A68: main (test.cc:92)
==9386==
==9386==
==9386== 4,006,240 bytes in 245 blocks are still reachable in loss record 6 of 7
==9386== at 0x4A059F6: malloc (vg_replace_malloc.c:149)
==9386== by 0x4C09F88: boost::memory::stdlib_alloc::allocate(unsigned long) (system_alloc.hpp:67)
==9386== by 0x4C0A033: boost::memory::system_pool_imp<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:141)
==9386== by 0x4C0A059: boost::memory::system_pool_s<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:181)
==9386== by 0x4C09BE0: _boost_SystemPoolAlloc (system_pool.cpp:24)
==9386== by 0x4022CE: std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, boost::memory::stl_allocator<std::pair<int const, int>, boost::memory::region_alloc<boost::memory::policy::pool> > >::_M_insert(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*, std::pair<int const, int> const&) (system_alloc.hpp:139)
==9386== by 0x402377: std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, boost::memory::stl_allocator<std::pair<int const, int>, boost::memory::region_alloc<boost::memory::policy::pool> > >::insert_unique(std::pair<int const, int> const&) (stl_tree.h:931)
==9386== by 0x400EEA: testMap() (stl_map.h:396)
==9386== by 0x401A68: main (test.cc:92)
==9386==
==9386==
==9386== 6,867,840 bytes in 420 blocks are indirectly lost in loss record 7 of 7
==9386== at 0x4A059F6: malloc (vg_replace_malloc.c:149)
==9386== by 0x4C09F88: boost::memory::stdlib_alloc::allocate(unsigned long) (system_alloc.hpp:67)
==9386== by 0x4C0A033: boost::memory::system_pool_imp<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:141)
==9386== by 0x4C0A059: boost::memory::system_pool_s<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:181)
==9386== by 0x4C09BE0: _boost_SystemPoolAlloc (system_pool.cpp:24)
==9386== by 0x40199C: testDeque() (system_alloc.hpp:139)
==9386== by 0x401A48: testStlContainers() (test.cc:84)
==9386== by 0x401A68: main (test.cc:92)
==9386==
==9386== LEAK SUMMARY:
==9386== definitely lost: 64 bytes in 4 blocks.
==9386== indirectly lost: 6,867,840 bytes in 420 blocks.
==9386== possibly lost: 16,352 bytes in 1 blocks.
==9386== still reachable: 4,006,240 bytes in 245 blocks.
==9386== suppressed: 0 bytes in 0 blocks.
[newpeak@localhost stdext-2.2.00]$ valgrind --tool=memcheck --show-reachable=yes --leak-check=full ./main >1.txt
==9423== Memcheck, a memory error detector.
==9423== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==9423== Using LibVEX rev 1732, a library for dynamic binary translation.
==9423== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==9423== Using valgrind-3.2.3, a dynamic binary instrumentation framework.
==9423== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==9423== For more details, rerun with: -v
==9423==
==9423==
==9423== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 5 from 1)
==9423== malloc/free: in use at exit: 10,890,496 bytes in 670 blocks.
==9423== malloc/free: 670 allocs, 0 frees, 10,890,496 bytes allocated.
==9423== For counts of detected errors, rerun with: -v
==9423== searching for pointers to 670 not-freed blocks.
==9423== checked 3,393,752 bytes.
==9423==
==9423== 16 bytes in 1 blocks are definitely lost in loss record 1 of 7
==9423== at 0x4A06205: operator new(unsigned long) (vg_replace_malloc.c:167)
==9423== by 0x400FC1: testMap() (tls.hpp:137)
==9423== by 0x401A68: main (test.cc:92)
==9423==
==9423==
==9423== 441,520 (16 direct, 441,504 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 7
==9423== at 0x4A06205: operator new(unsigned long) (vg_replace_malloc.c:167)
==9423== by 0x40196A: testDeque() (tls.hpp:137)
==9423== by 0x401A48: testStlContainers() (test.cc:84)
==9423== by 0x401A68: main (test.cc:92)
==9423==
==9423==
==9423== 2,403,760 (16 direct, 2,403,744 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 7
==9423== at 0x4A06205: operator new(unsigned long) (vg_replace_malloc.c:167)
==9423== by 0x4016CC: testList() (tls.hpp:137)
==9423== by 0x401A4D: testStlContainers() (test.cc:85)
==9423== by 0x401A68: main (test.cc:92)
==9423==
==9423==
==9423== 4,022,608 (16 direct, 4,022,592 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 7
==9423== at 0x4A06205: operator new(unsigned long) (vg_replace_malloc.c:167)
==9423== by 0x4011D0: testSet() (tls.hpp:137)
==9423== by 0x401A52: testStlContainers() (test.cc:86)
==9423== by 0x401A68: main (test.cc:92)
==9423==
==9423==
==9423== 16,352 bytes in 1 blocks are possibly lost in loss record 5 of 7
==9423== at 0x4A059F6: malloc (vg_replace_malloc.c:149)
==9423== by 0x4C09F88: boost::memory::stdlib_alloc::allocate(unsigned long) (system_alloc.hpp:67)
==9423== by 0x4C0A033: boost::memory::system_pool_imp<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:141)
==9423== by 0x4C0A059: boost::memory::system_pool_s<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:181)
==9423== by 0x4C09BE0: _boost_SystemPoolAlloc (system_pool.cpp:24)
==9423== by 0x400FF3: testMap() (system_alloc.hpp:139)
==9423== by 0x401A68: main (test.cc:92)
==9423==
==9423==
==9423== 4,006,240 bytes in 245 blocks are still reachable in loss record 6 of 7
==9423== at 0x4A059F6: malloc (vg_replace_malloc.c:149)
==9423== by 0x4C09F88: boost::memory::stdlib_alloc::allocate(unsigned long) (system_alloc.hpp:67)
==9423== by 0x4C0A033: boost::memory::system_pool_imp<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:141)
==9423== by 0x4C0A059: boost::memory::system_pool_s<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:181)
==9423== by 0x4C09BE0: _boost_SystemPoolAlloc (system_pool.cpp:24)
==9423== by 0x4022CE: std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, boost::memory::stl_allocator<std::pair<int const, int>, boost::memory::region_alloc<boost::memory::policy::pool> > >::_M_insert(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*, std::pair<int const, int> const&) (system_alloc.hpp:139)
==9423== by 0x402377: std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, boost::memory::stl_allocator<std::pair<int const, int>, boost::memory::region_alloc<boost::memory::policy::pool> > >::insert_unique(std::pair<int const, int> const&) (stl_tree.h:931)
==9423== by 0x400EEA: testMap() (stl_map.h:396)
==9423== by 0x401A68: main (test.cc:92)
==9423==
==9423==
==9423== 6,867,840 bytes in 420 blocks are indirectly lost in loss record 7 of 7
==9423== at 0x4A059F6: malloc (vg_replace_malloc.c:149)
==9423== by 0x4C09F88: boost::memory::stdlib_alloc::allocate(unsigned long) (system_alloc.hpp:67)
==9423== by 0x4C0A033: boost::memory::system_pool_imp<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:141)
==9423== by 0x4C0A059: boost::memory::system_pool_s<boost::memory::policy::stdlib, boost::memory::normal_stack>::allocate(unsigned long) (system_pool.hpp:181)
==9423== by 0x4C09BE0: _boost_SystemPoolAlloc (system_pool.cpp:24)
==9423== by 0x40199C: testDeque() (system_alloc.hpp:139)
==9423== by 0x401A48: testStlContainers() (test.cc:84)
==9423== by 0x401A68: main (test.cc:92)
==9423==
==9423== LEAK SUMMARY:
==9423== definitely lost: 64 bytes in 4 blocks.
==9423== indirectly lost: 6,867,840 bytes in 420 blocks.
==9423== possibly lost: 16,352 bytes in 1 blocks.
==9423== still reachable: 4,006,240 bytes in 245 blocks.
==9423== suppressed: 0 bytes in 0 blocks.
因此在目前看来我是不敢将boost::memory 引入项目的
此外,对boost::memory有个建议,能否把所有实现都放入头文件中?
因为如果它还没有被放到boost库中,那么对于使用者是非常不便的,每台使用该库的程序都要单独编译boost::memory,然后才能供其他程序使用
Best
Yingfeng
你好
关于3 是我的疏忽,auto_alloc和scoped_alloc,在simple_example里是没有内存泄露的,但testGCAlloc和testTlsScopedAlloc确实有泄露,内容在第二封邮件里已有描述
stl_container的相关测试内存确实有泄露
你是说不该相信valgrind的检测结果?
更多反馈会逐渐给出,因为目前在mac 平台上,此前的测试程序都没办法跑了,还在逐条排除中
2008/12/10 shiwei xu <xushi...@gmail.com>
应当是系统设计问题导致的内存漏洞:
template <class AllocT, class TlsAllocT>
class proxy_alloc
{
private:
AllocT* m_alloc;
public:
proxy_alloc() : m_alloc(&TlsAllocT::instance()) {}
}
在这里m_alloc 调用了 TlsAllocT::instance来获得一个block_pool的实例,初次调用应当会new 一个实例对象出来
template <class Unused>
class tls_block_pool_imp
{
private:
static tls_block_pool_t* _tls_blockPool;
public:
tls_block_pool_imp() {
//这里没有调用
_tls_blockPool->init();
}
~tls_block_pool_imp() {
//这里没有调用
_tls_blockPool->term();
}
static block_pool& BOOST_MEMORY_CALL instance()
{
return _tls_blockPool->get();
}
};
在这里, instance方法是静态方法,直接 get() 返回了
tls_block_pool_imp 的构造器和析构函数没有被调用,也就是 _tls_blockPool->term() 没有起到作用,因此 _tls_blockPool->get()生成的对象没有被cleanup
我在上面注释的地方还有tls.hpp里所有可能的地方都加了log,证明了我的判断
这就解释了为什么我把tls_block_pool_t换成block_pool就没有泄露了
2008/12/11 Yingfeng Zhang <yingfen...@gmail.com>
我尝试了一下
你在block_pool中的singleton:
tls_block_pool_t g_tls_blockPool;
如果把它改成
block_pool g_blockPool;
同时tls_block_pool_imp里相应tls_block_pool_t的动作去掉
这样的话,即便采用
boost::scoped_alloc alloc;
根据valgrind也不会有内存泄露了
所以我决定看看是不是tls_object 的实现有问题先
Sorry 应当是我的疏忽
class tls_block_pool_init的存在确保了tls对象的正确使用,不过我把它给注释掉了
Btw: 目前我把.cpp文件里的singleton移到了.h文件中,此外还有一些.cpp的依赖给排除,这样尽管全局变量的声明和定义都在一起,但由于这些全局变量并没有放在接口文件memory.hpp中,因此在项目中应当不会被包含多次导致重复定义, 目前看来,似乎可用了。
关于mac os X,主要需要这么几个修改
1 mac os X的malloc.h通常位于 /usr/include/malloc/malloc.h下,而不是 常规的/usr/include/malloc.h,因此要么 include <malloc/malloc.h> ,要么用户手动做一个 ln -s /usr/include/malloc/malloc.h /usr/include/malloc.h
2 pthread.hpp中的GetCurrentThreadId函数,需要 (DWORD)(pthread_self()->__sig); 因为 pthread_self()的返回类型是个指向某个结构的指针
3 system_alloc.hpp中 _msize的定义是malloc_usable_size,这个函数在mac os x下无效,因此暂时用malloc_size来代替
4 basic.hpp中 #pragma pack() 会跟mac os X的系统文件定义重复,在mac 下暂时把这个宏去掉
5 最后一个修改暂时还没进行, 是如果把scoped_alloc应用于std::map时,模板匹配出问题,以后有空再做相关修正。
2008/12/11 Yingfeng Zhang <yingfen...@gmail.com>
2008/12/10 shiwei xu <xushi...@gmail.com>
这种错误我以前也见过,并非真正意义上的内存泄漏。其根本原因仍然在那个 singleton 的 block_pool 上。因为内存释放时被"还"给了这个 block_pool 而没有真正释放。而该 block_pool 在程序退出时释放(其实就算没有释放操作也无所谓了,因为程序正在退出)。
2008/12/11 Yingfeng Zhang <yingfen...@gmail.com>
2008/12/10 shiwei xu <xushi...@gmail.com>
这种错误我以前也见过,并非真正意义上的内存泄漏。其根本原因仍然在那个 singleton 的 block_pool 上。因为内存释放时被"还"给了这个 block_pool 而没有真正释放。而该 block_pool 在程序退出时释放(其实就算没有释放操作也无所谓了,因为程序正在退出)。
我觉得是没有问题的。
两个模块使用同样的符号,在链接时会合并的,不过可以测试一下, :-)
--
Best Regards,
LI Daobing
$ make
g++ -shared -o b.so b.cpp
g++ -shared -o c.so c.cpp
g++ -o d d.cpp b.so c.so
LD_LIBRARY_PATH=. ./d
a1: 0x9912028, a2: 0x9912028
确认 dlopen 结果不同,测试案例见附件。 e 的结果就是 dlopen 的,结果是不一样,链接是没有问题的。
不过我觉得 dlopen 时用户应当自行考虑这个问题。
$ make
g++ -shared -o b.so b.cpp
g++ -shared -o c.so c.cpp
g++ -o d d.cpp b.so c.so
g++ -g -o e e.cpp -ldl
LD_LIBRARY_PATH=. ./d
a1: 0x9896028, a2: 0x9896028
LD_LIBRARY_PATH=. ./e
a1: 0x89093b0
a2: 0x8909758
一般来讲,设计库的时候会打一个版本戳,可以减少这种问题,比如后面 @@DB4_6 就是版本戳。
这样不仅可以避免你的问题,而且如果你的两个 .so 一个用 db4.5 编译,一个用 db4.6 编译,那么仍然可以同时使用。
$ readelf -a /usr/lib/libdb-4.6.so | grep @@ | head
137: 00078af0 571 FUNC GLOBAL DEFAULT 12
__repmgr_set_local_site@@DB4_6
138: 001121d0 997 FUNC GLOBAL DEFAULT 12 __txn_checkpoint@@DB4_6
139: 0005a5d0 164 FUNC GLOBAL DEFAULT 12 __qam_pgin_out@@DB4_6
140: 000a3ad0 24 FUNC GLOBAL DEFAULT 12 __dbcl_dbc_count_ret@@DB4_6
141: 000d9420 83 FUNC GLOBAL DEFAULT 12 __env_set_tmp_dir@@DB4_6
142: 000c16d0 1738 FUNC GLOBAL DEFAULT 12 __db_open@@DB4_6
143: 000d3f60 935 FUNC GLOBAL DEFAULT 12 __dbreg_register_log@@DB4_6
144: 000a3a50 34 FUNC GLOBAL DEFAULT 12
__dbcl_db_key_range_ret@@DB4_6
145: 00092770 242 FUNC GLOBAL DEFAULT 12 __mutex_alloc_pp@@DB4_6
146: 000d9500 267 FUNC GLOBAL DEFAULT 12 __env_set_data_dir@@DB4_6
-Bsymbolic
When creating a shared library, bind references to global
symbols to the definition within the shared library, if any.
Normally, it is possible for a program linked against a shared library
to override the definition within the shared library. This option is
only meaningful on ELF platforms which support shared libraries.
-Bsymbolic-functions
When creating a shared library, bind references to global
function symbols to the definition within the shared library, if any.
This option is only meaningful on ELF platforms which support shared
libraries.