为什么 valgrind 在 none 时会在这里看到内存泄漏
Why does valgrind see a memory leak here when there is none
我有以下一段C++代码,暂时忽略在程序中实际执行此操作的不良做法。
#include<iostream>
//#include <type_traits>
using namespace std;
class P{
public:
void rebase(P* self);
virtual void print();
virtual ~P(){}
};
class C: public P{
virtual void print();
};
void P::rebase(P* self){
//memory leak is detected, but no leak actually happens
delete self;
self=new C();
}
void P::print(){
cout<<"P"<<endl;
}
void C::print(){
cout<<"C"<<endl;
}
int main(){
P *test;
test= new P();
test->print();
for(int i=0;i<10000;i++) test->rebase(test);//run the "leaking" code 10000 times to amplify any leak
test->print();
delete test;
while (true);//blocks program from stoping so we can look at it with pmap
}
我通过 valgrind 发送了这段 jenky 代码,它在 P::rebase() 中报告了内存泄漏,但是当我查看内存使用情况时没有泄漏,为什么 valgrind 认为有?
==5547== LEAK SUMMARY:
==5547== definitely lost: 80,000 bytes in 10,000 blocks
==5547== indirectly lost: 0 bytes in 0 blocks
==5547== possibly lost: 0 bytes in 0 blocks
==5547== still reachable: 72,704 bytes in 1 blocks
==5547== suppressed: 0 bytes in 0 blocks
==5547== Rerun with --leak-check=full to see details of leaked memory
==5547==
==5547== For counts of detected and suppressed errors, rerun with: -v
==5547== ERROR SUMMARY: 30001 errors from 7 contexts (suppressed: 0 from 0)
我用 sudo pmap -x
仔细检查过,没有泄漏
total kB 13272 2956 180
你确实有内存泄漏。
的问题
void P::rebase(P* self){
//memory leak is detected, but no leak actually happens
delete self;
self=new C();
}
你是按值传递指针吗?这意味着来自 main 的指针永远不会重新分配新地址,并且您实际上会丢失它,因为 self
在函数结束时超出范围。如果你使用
void P::rebase(P*& self){
//memory leak is detected, but no leak actually happens
delete self;
self=new C();
}
通过引用传递指针的地方不会有内存泄漏。
你的函数中也有 undefined 因为你一直在 main 的指针上调用 delete 并且不止一次在指针上调用 delete,如果它不为 null,就是未定义的行为。
基本上您的代码与
相同
int* a = new int;
for (int i = 0; i < 10000; i++)
{
int* b = a; // we copy the address held by a
delete b; // uh oh we call delete on that same address again
b = new int; // put new memory in b, this does nothing to a
} // leak here as b goes out of scope and we no longer have the address it held
Valgrind 是正确的。
void P::rebase(P* self){
//memory leak is detected, but no leak actually happens
delete self;
self=new C();
}
这有两个问题 - 它没有 return 指向程序的新指针
它删除了一个 运行 对象。
删除 运行 对象可能会导致函数末尾的代码崩溃,因为需要对象引用才能离开函数。
代码可能会在调用 test->print() 时崩溃。我认为编译器是 re-using 两个对象的内存。如果你把它们换过来,例如
P* old = self;
self=new C();
delete old;
那就不行了
对测试的 non-virtual 调用将起作用,但会导致未定义的行为。由于真实对象在第一次调用后已经销毁。
Valgrind 是一个软件,它有自己的逻辑,如果它的某些条件满足它认为是内存泄漏,它会根据它的逻辑创建警告列表。不一定是完美的内存泄漏。如果您认为可以忽略此类警告,则可以直接忽略它。
但在你的情况下我可以看到明显的内存泄漏。您从 class C
实例化了一个对象,并且您永远不会释放内存。这就是为什么在 C++ 中我们鼓励使用智能指针来避免此类错误的原因。
self=new C();
我有以下一段C++代码,暂时忽略在程序中实际执行此操作的不良做法。
#include<iostream>
//#include <type_traits>
using namespace std;
class P{
public:
void rebase(P* self);
virtual void print();
virtual ~P(){}
};
class C: public P{
virtual void print();
};
void P::rebase(P* self){
//memory leak is detected, but no leak actually happens
delete self;
self=new C();
}
void P::print(){
cout<<"P"<<endl;
}
void C::print(){
cout<<"C"<<endl;
}
int main(){
P *test;
test= new P();
test->print();
for(int i=0;i<10000;i++) test->rebase(test);//run the "leaking" code 10000 times to amplify any leak
test->print();
delete test;
while (true);//blocks program from stoping so we can look at it with pmap
}
我通过 valgrind 发送了这段 jenky 代码,它在 P::rebase() 中报告了内存泄漏,但是当我查看内存使用情况时没有泄漏,为什么 valgrind 认为有?
==5547== LEAK SUMMARY:
==5547== definitely lost: 80,000 bytes in 10,000 blocks
==5547== indirectly lost: 0 bytes in 0 blocks
==5547== possibly lost: 0 bytes in 0 blocks
==5547== still reachable: 72,704 bytes in 1 blocks
==5547== suppressed: 0 bytes in 0 blocks
==5547== Rerun with --leak-check=full to see details of leaked memory
==5547==
==5547== For counts of detected and suppressed errors, rerun with: -v
==5547== ERROR SUMMARY: 30001 errors from 7 contexts (suppressed: 0 from 0)
我用 sudo pmap -x
仔细检查过,没有泄漏
total kB 13272 2956 180
你确实有内存泄漏。
的问题void P::rebase(P* self){
//memory leak is detected, but no leak actually happens
delete self;
self=new C();
}
你是按值传递指针吗?这意味着来自 main 的指针永远不会重新分配新地址,并且您实际上会丢失它,因为 self
在函数结束时超出范围。如果你使用
void P::rebase(P*& self){
//memory leak is detected, but no leak actually happens
delete self;
self=new C();
}
通过引用传递指针的地方不会有内存泄漏。
你的函数中也有 undefined 因为你一直在 main 的指针上调用 delete 并且不止一次在指针上调用 delete,如果它不为 null,就是未定义的行为。
基本上您的代码与
相同int* a = new int;
for (int i = 0; i < 10000; i++)
{
int* b = a; // we copy the address held by a
delete b; // uh oh we call delete on that same address again
b = new int; // put new memory in b, this does nothing to a
} // leak here as b goes out of scope and we no longer have the address it held
Valgrind 是正确的。
void P::rebase(P* self){
//memory leak is detected, but no leak actually happens
delete self;
self=new C();
}
这有两个问题 - 它没有 return 指向程序的新指针 它删除了一个 运行 对象。
删除 运行 对象可能会导致函数末尾的代码崩溃,因为需要对象引用才能离开函数。
代码可能会在调用 test->print() 时崩溃。我认为编译器是 re-using 两个对象的内存。如果你把它们换过来,例如
P* old = self;
self=new C();
delete old;
那就不行了
对测试的 non-virtual 调用将起作用,但会导致未定义的行为。由于真实对象在第一次调用后已经销毁。
Valgrind 是一个软件,它有自己的逻辑,如果它的某些条件满足它认为是内存泄漏,它会根据它的逻辑创建警告列表。不一定是完美的内存泄漏。如果您认为可以忽略此类警告,则可以直接忽略它。
但在你的情况下我可以看到明显的内存泄漏。您从 class C
实例化了一个对象,并且您永远不会释放内存。这就是为什么在 C++ 中我们鼓励使用智能指针来避免此类错误的原因。
self=new C();