我碰到下面的问题就来了我的代码:我用Valgrind的和gperftools执行堆检查和堆纹,看看我是否释放所有我分配内存。 这些工具的输出好看,似乎我没有失去记忆。 然而,当我看着top
的输出和ps
我很困惑,因为这根本不能代表什么,我用的valgrind和gperftools观察。
下面是数字:
- 热门报告:RES 150M
- Valgrind的(地块)报道:23M峰值使用
- gperftools堆分析器报道:峰值2270万使用
我的问题是现在,哪里的差别从何而来? 我试着以及跟踪Valgrind的,但没有任何成功的堆栈使用。
一些细节:
- 该过程基本上从MySQL通过C API负载数据,以在内存中存储
- 执行泄漏检查,打破不久装载完成后,显示了一个明确的失去的144个字节,可达10M,至极适合当前分配量
- 该库不执行任何复杂的IPC,它启动一个线程数,但只有一个线程在执行工作
- 这不加载其他复杂的系统库
- 从/ proc / PID / smaps的PSS大小对应于在TOP和ps的RES大小
你有什么想法,其中在报告的内存消耗这种差异从何而来? 我如何可以验证我的程序行为正确? 你有什么想法如何,我会进一步调查此问题?
最后,我能够解决的问题,并会很乐意分享我的发现。 一般来说,以评估从我的角度程序的内存消耗的最佳工具是地块从Valgrind的工具。 它允许您分析堆消耗,给你一个详细的分析。
要分析你的应用程序运行的堆valgrind --tool=massif prog
现在,这会给你有关,如典型内存分配功能的全部信息基本访问malloc
和朋友。 然而,深入挖掘我激活的选项--pages-as-heap=yes
这将然后报告甚至对下伏系统调用的信息。 为了给出一个例子这里是从我的分析会话的内容:
67 1,284,382,720 978,575,360 978,575,360 0 0
100.00% (978,575,360B) (page allocation syscalls) mmap/mremap/brk, --alloc-fns, etc.
->87.28% (854,118,400B) 0x8282419: mmap (syscall-template.S:82)
| ->84.80% (829,849,600B) 0x821DF7D: _int_malloc (malloc.c:3226)
| | ->84.36% (825,507,840B) 0x821E49F: _int_memalign (malloc.c:5492)
| | | ->84.36% (825,507,840B) 0x8220591: memalign (malloc.c:3880)
| | | ->84.36% (825,507,840B) 0x82217A7: posix_memalign (malloc.c:6315)
| | | ->83.37% (815,792,128B) 0x4C74F9B: std::_Rb_tree_node<std::pair<std::string const, unsigned int> >* std::_Rb_tree<std::string, std::pair<std::string const, unsigned int>, std::_Select1st<std::pair<std::string const, unsigned int> >, std::less<std::string>, StrategizedAllocator<std::pair<std::string const, unsigned int>, MemalignStrategy<4096> > >::_M_create_node<std::pair<std::string, unsigned int> >(std::pair<std::string, unsigned int>&&) (MemalignStrategy.h:13)
| | | | ->83.37% (815,792,128B) 0x4C7529F: OrderIndifferentDictionary<std::string, MemalignStrategy<4096>, StrategizedAllocator>::addValue(std::string) (stl_tree.h:961)
| | | | ->83.37% (815,792,128B) 0x5458DC9: var_to_string(char***, unsigned long, unsigned long, AbstractTable*) (AbstractTable.h:341)
| | | | ->83.37% (815,792,128B) 0x545A466: MySQLInput::load(std::shared_ptr<AbstractTable>, std::vector<std::vector<ColumnMetadata*, std::allocator<ColumnMetadata*> >*, std::allocator<std::vector<ColumnMetadata*, std::allocator<ColumnMetadata*> >*> > const*, Loader::params const&) (MySQLLoader.cpp:161)
| | | | ->83.37% (815,792,128B) 0x54628F2: Loader::load(Loader::params const&) (Loader.cpp:133)
| | | | ->83.37% (815,792,128B) 0x4F6B487: MySQLTableLoad::executePlanOperation() (MySQLTableLoad.cpp:60)
| | | | ->83.37% (815,792,128B) 0x4F8F8F1: _PlanOperation::execute_throws() (PlanOperation.cpp:221)
| | | | ->83.37% (815,792,128B) 0x4F92B08: _PlanOperation::execute() (PlanOperation.cpp:262)
| | | | ->83.37% (815,792,128B) 0x4F92F00: _PlanOperation::operator()() (PlanOperation.cpp:204)
| | | | ->83.37% (815,792,128B) 0x656F9B0: TaskQueue::executeTask() (TaskQueue.cpp:88)
| | | | ->83.37% (815,792,128B) 0x7A70AD6: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
| | | | ->83.37% (815,792,128B) 0x6BAEEFA: start_thread (pthread_create.c:304)
| | | | ->83.37% (815,792,128B) 0x8285F4B: clone (clone.S:112)
| | | |
| | | ->00.99% (9,715,712B) in 1+ places, all below ms_print's threshold (01.00%)
| | |
| | ->00.44% (4,341,760B) in 1+ places, all below ms_print's threshold (01.00%)
正如你可以看到我的〜内存分配的85%,从单枝来,现在的问题是,为什么内存消耗如此之高,如果原来的堆纹表现出了正常的消费。 如果你看一下例子你就会明白为什么。 对于分配我用posix_memalign
,以确保拨款发生有用的边界。 这个分配器然后从外部类到内部构件的变量(一个地图在这种情况下)向下传递到用于堆分配的分配器。 不过,我选择的边界太大 - 4096 - 在我的情况。 这意味着,你将分配4B使用posix_memalign
但系统会分配一个完整的网页让你正确对齐。 如果你现在分配许多小的值,您将结束大量未使用的内存。 该内存不会被正常的堆分析工具来报道,因为你只分配此内存的一小部分,但系统配置程序将分配更多的和隐藏的休息。
为了解决这个问题,我切换到一个较小的边界,从而可以大大降低内存开销。
由于在地块与公司前度过我的时间的结论,我只能建议使用此工具,深剖析,因为它可以让你发生了什么事的一个很好的理解和允许容易跟踪误差。 对于使用posix_memalign
情况就不同了。 在有些情况下确实有必要的情况下,然而,在大多数情况下,你只用普通细malloc
。
根据该文章的PS /顶部报告多少内存的程序使用,如果它是唯一的程序运行。 假设你的程序例如使用一堆共享库如STL这是已经加载到存储器的存在被由于VS分配给你的程序的执行,如果它是它会多少内存分配的实际存储量之间的间隙唯一的过程。
默认情况下,地块只报告堆大小。 TOP报告在存储器实际尺寸,包括由程序代码本身以及堆栈大小所使用的尺寸。
尝试与供应地块--stacks=yes
选项,告诉它报告的总内存使用情况,包括堆栈空间,看看这改变了吗?