valgrind/massif看不到从另一个线程完成的内存交易。
在用Valgrind/massif分析内存使用时,我发现它似乎看不到从另一个线程完成的内存Deallocation,将其报告为泄漏。 这是一个证明:
#include <stdio.h>
#include <iostream>
#include <pthread.h>
#include <stdlib.h>
using namespace std;
struct my_struct
{
pthread_mutex_t m_mutex;
void* m_mem;
};
extern "C"
{
void* my_allocation(void* p)
{
my_struct *ptr = (my_struct*)p;
int error;
if((error = pthread_mutex_lock(&ptr->m_mutex))) {
cerr << "mutex lock failed in thread: " << error << endl;
}
else {
ptr->m_mem = malloc(100);
if((error = pthread_mutex_unlock(&ptr->m_mutex)))
cerr << "mutex unlock failed in thread: " << error << endl;
}
return NULL;
}
void* my_deallocation(void* p)
{
my_struct *ptr = (my_struct*)p;
int error;
if((error = pthread_mutex_lock(&ptr->m_mutex))) {
cerr << "mutex lock failed in thread: " << error << endl;
}
else {
free(ptr->m_mem);
ptr->m_mem = NULL;
if((error = pthread_mutex_unlock(&ptr->m_mutex)))
cerr << "mutex unlock failed in thread: " << error << endl;
}
return NULL;
}
}
int main(int argc, char **argv)
{
pthread_t alloc_thread;
pthread_t dealloc_thread;
my_struct value;
value.m_mem = NULL;
int error;
if((error = pthread_mutex_init(&value.m_mutex, NULL))) {
cerr << "Failed to initialize mutex: " << error << endl;
return 1;
}
for(int i=0; i<300; ++i) {
if((error = pthread_create(&alloc_thread, NULL, my_allocation, &value))) {
cerr << "Failed to start allocation thread: " << error << endl;
return 1;
}
if((error = pthread_join(alloc_thread, NULL))) {
cerr << "Failed to join allocation thread: " << error << endl;
return 1;
}
if((error = pthread_mutex_lock(&value.m_mutex))) {
cerr << "mutex lock failed: " << error << endl;
}
else {
if(!value.m_mem) {
cerr << "Allocation thread failed to allocate the memory" << endl;
return 1;
}
if((error = pthread_mutex_unlock(&value.m_mutex)))
cerr << "mutex unlock failed: " << error << endl;
}
if((error = pthread_create(&dealloc_thread, NULL, my_deallocation, &value))) {
cerr << "Failed to start deallocation thread: " << error << endl;
return 1;
}
if((error = pthread_join(dealloc_thread, NULL))) {
cerr << "Failed to join deallocation thread: " << error << endl;
return 1;
}
if((error = pthread_mutex_lock(&value.m_mutex))) {
cerr << "mutex lock failed: " << error << endl;
}
else {
if(value.m_mem) {
cerr << "Deallocation thread failed to deallocate the memory" << endl;
return 1;
}
if((error = pthread_mutex_unlock(&value.m_mutex)))
cerr << "mutex unlock failed: " << error << endl;
}
}
if((error = pthread_mutex_destroy(&value.m_mutex))) {
cerr << "Failed to destroy mutex: " << error << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
在Valgrind/massif下运行此程序后,我得到的报告似乎表明分配的内存为泄漏。
这是massif报告的片段:
--------------------------------------------------------------------------------
Command: valgrind-threads
Massif arguments: --heap=yes --pages-as-heap=yes --massif-out-file=/tmp/valgrind-threads.massif.31220.log
ms_print arguments: /tmp/valgrind-threads.massif.31220.log
--------------------------------------------------------------------------------
100.00% (197,083,136B) (page allocation syscalls) mmap/mremap/brk, --alloc-fns, etc.
->72.36% (142,610,432B) 0x7773FCA: mmap (in /usr/lib64/libc-2.17.so)
| ->68.10% (134,217,728B) 0x76FA2D0: new_heap (in /usr/lib64/libc-2.17.so)
| | ->68.10% (134,217,728B) 0x76FA8D3: arena_get2.isra.3 (in /usr/lib64/libc-2.17.so)
| | ->68.10% (134,217,728B) 0x770077D: malloc (in /usr/lib64/libc-2.17.so)
| | ->68.10% (134,217,728B) 0x40C194: my_allocation (valgrind-threads.cpp:24)
| | ->68.10% (134,217,728B) 0x7466EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
| | ->68.10% (134,217,728B) 0x7779B0C: clone (in /usr/lib64/libc-2.17.so)
| |
| ->04.26% (8,392,704B) 0x74677FC: pthread_create@@GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
| | ->04.26% (8,392,704B) 0x40C384: main (valgrind-threads.cpp:64)
| |
| ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
valgrind版本是3.19
。 用GCC 4.9.4
在Red Hat Enterprise Linux服务器版本7.9(Maipo)
上构建和运行。
我是错误地阅读报告,还是是valgrind/massif限制,还是我在代码中做错了什么?
While profiling the memory usage with valgrind/massif, I found it does not seem to see the memory deallocation done from another thread, reporting it as a leak.
Here is an program that demonstrates that:
#include <stdio.h>
#include <iostream>
#include <pthread.h>
#include <stdlib.h>
using namespace std;
struct my_struct
{
pthread_mutex_t m_mutex;
void* m_mem;
};
extern "C"
{
void* my_allocation(void* p)
{
my_struct *ptr = (my_struct*)p;
int error;
if((error = pthread_mutex_lock(&ptr->m_mutex))) {
cerr << "mutex lock failed in thread: " << error << endl;
}
else {
ptr->m_mem = malloc(100);
if((error = pthread_mutex_unlock(&ptr->m_mutex)))
cerr << "mutex unlock failed in thread: " << error << endl;
}
return NULL;
}
void* my_deallocation(void* p)
{
my_struct *ptr = (my_struct*)p;
int error;
if((error = pthread_mutex_lock(&ptr->m_mutex))) {
cerr << "mutex lock failed in thread: " << error << endl;
}
else {
free(ptr->m_mem);
ptr->m_mem = NULL;
if((error = pthread_mutex_unlock(&ptr->m_mutex)))
cerr << "mutex unlock failed in thread: " << error << endl;
}
return NULL;
}
}
int main(int argc, char **argv)
{
pthread_t alloc_thread;
pthread_t dealloc_thread;
my_struct value;
value.m_mem = NULL;
int error;
if((error = pthread_mutex_init(&value.m_mutex, NULL))) {
cerr << "Failed to initialize mutex: " << error << endl;
return 1;
}
for(int i=0; i<300; ++i) {
if((error = pthread_create(&alloc_thread, NULL, my_allocation, &value))) {
cerr << "Failed to start allocation thread: " << error << endl;
return 1;
}
if((error = pthread_join(alloc_thread, NULL))) {
cerr << "Failed to join allocation thread: " << error << endl;
return 1;
}
if((error = pthread_mutex_lock(&value.m_mutex))) {
cerr << "mutex lock failed: " << error << endl;
}
else {
if(!value.m_mem) {
cerr << "Allocation thread failed to allocate the memory" << endl;
return 1;
}
if((error = pthread_mutex_unlock(&value.m_mutex)))
cerr << "mutex unlock failed: " << error << endl;
}
if((error = pthread_create(&dealloc_thread, NULL, my_deallocation, &value))) {
cerr << "Failed to start deallocation thread: " << error << endl;
return 1;
}
if((error = pthread_join(dealloc_thread, NULL))) {
cerr << "Failed to join deallocation thread: " << error << endl;
return 1;
}
if((error = pthread_mutex_lock(&value.m_mutex))) {
cerr << "mutex lock failed: " << error << endl;
}
else {
if(value.m_mem) {
cerr << "Deallocation thread failed to deallocate the memory" << endl;
return 1;
}
if((error = pthread_mutex_unlock(&value.m_mutex)))
cerr << "mutex unlock failed: " << error << endl;
}
}
if((error = pthread_mutex_destroy(&value.m_mutex))) {
cerr << "Failed to destroy mutex: " << error << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
After running this program under valgrind/massif, I am getting the report that seems to indicate the allocated memory as leaked.
Here is a fragment of massif report:
--------------------------------------------------------------------------------
Command: valgrind-threads
Massif arguments: --heap=yes --pages-as-heap=yes --massif-out-file=/tmp/valgrind-threads.massif.31220.log
ms_print arguments: /tmp/valgrind-threads.massif.31220.log
--------------------------------------------------------------------------------
100.00% (197,083,136B) (page allocation syscalls) mmap/mremap/brk, --alloc-fns, etc.
->72.36% (142,610,432B) 0x7773FCA: mmap (in /usr/lib64/libc-2.17.so)
| ->68.10% (134,217,728B) 0x76FA2D0: new_heap (in /usr/lib64/libc-2.17.so)
| | ->68.10% (134,217,728B) 0x76FA8D3: arena_get2.isra.3 (in /usr/lib64/libc-2.17.so)
| | ->68.10% (134,217,728B) 0x770077D: malloc (in /usr/lib64/libc-2.17.so)
| | ->68.10% (134,217,728B) 0x40C194: my_allocation (valgrind-threads.cpp:24)
| | ->68.10% (134,217,728B) 0x7466EA4: start_thread (in /usr/lib64/libpthread-2.17.so)
| | ->68.10% (134,217,728B) 0x7779B0C: clone (in /usr/lib64/libc-2.17.so)
| |
| ->04.26% (8,392,704B) 0x74677FC: pthread_create@@GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
| | ->04.26% (8,392,704B) 0x40C384: main (valgrind-threads.cpp:64)
| |
| ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
Valgrind version is 3.19
.
Building and running that with gcc 4.9.4
on Red Hat Enterprise Linux Server release 7.9 (Maipo)
.
Am I reading the report incorrectly, or it is a valgrind/massif limitation, or I am doing something wrong in the code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如它在另一个问题< /a>我发布了有关valgrind/massif未跟踪的TLS Deleclations:
如果我们使用
-pages-as-as-heap
,Valgrind/massif将报告每个线程Malloc Cache分配的GLIBC内存页面,至少在线程上的第一个分配时(有时在需要生长时可能会发生重新分配)。这给人以分配的内存泄漏的印象。
如果没有
运行 - 页面
选项,则正确解释了交易。As it was found in another question I posted about TLS deallocations not tracked by valgrind/massif:
If we use
--pages-as-heap
, valgrind/massif will report the GLIBC memory pages allocated per thread malloc cache, which happens at least at the first allocation on thread (sometimes the reallocations may happen when heap needs to grow).This gives an impression the allocated memory has leaked.
If run without
--pages-as-heap
option, the deallocations are accounted for correctly.