内存泄漏的基本概念是代码执行期间新/删除操作的不匹配,可能是由于错误的编码实践,也可能是在跳过删除操作时出现错误。
但最近我在一次采访中被问到一个问题,关于记忆可以泄漏的其他方式。 我没有答案。它是什么?
答案 0 :(得分:16)
常见的动态内存问题是:
new
进行动态内存分配,而不是使用delete
取消分配。 new[]
分配动态内存,并使用delete
取消分配。 new
并将其与free
取消分配。 malloc
并将其与delete
取消分配。 除了内存泄漏/内存损坏之外,最后3种情况还会导致可怕的 Undefined Behavior 。
其他一些潜在的内存泄漏导致我可以回忆起的情况是:
代码示例:
char *a = new[128];
char *b = new[128];
b = a;
delete[]a;
delete[]b; // will not deallocate the pointer to the original allocated memory.
- STL容器中的指针
更常见且经常遇到的情况是,存储指向STL容器中动态分配类型的指针。请务必注意,只有当STL容器不是指针类型 时,STL容器才会删除所包含的对象 。 在删除容器本身之前,必须显式迭代容器并删除每个包含的类型。不这样做会导致内存泄漏 Here 就是这种情况的一个例子。
- 非虚拟基类析构函数问题
删除指向Base类的指针,该指针指向堆上派生类的任何动态分配对象。这会导致未定义的行为。
代码示例:
class MyClass
{
public:
virtual void doSomething(){}
};
class MyClass2 : public MyClass
{
private:
std::string str;
public: MyClass2( std::string& s)
{
str=s;
}
virtual void doSomething(){}
};
int main()
{
std::str hello("hello");
MyClass * p = new MyClass2(hello);
if( p )
{
delete p;
}
return 0;
}
在示例中,只调用析构函数MyClass ::〜MyClass(),并且永远不会调用MyClass2 :: ~MyClass2()。为了适当的解除分配,我们需要,
MyClass::virtual ~MyClass(){}
- 在delete
指针上调用void
代码示例:
void doSomething( void * p )
{
//do something interesting
if(p)
delete p;
}
int main()
{
A* p = new A();
doSomething(p);
return 0;
}
如上例所示,在delete
指针上调用void
将导致内存泄漏和未定义行为。
答案 1 :(得分:4)
作为面试问题,面试官可能一直在寻找比教科书新/删除不匹配更广泛的观点。
任何超出最后一点所需的内存都可以被视为“泄露”。最终可以通过代码中的删除进行手动释放此内存,使这些泄漏成为临时泄漏,而不是使用不匹配的新/删除操作符时遇到的永久性泄漏。在“泄漏”持续的持续时间内,净效应是相同的。您正在减少程序其他部分的可用资源(内存)。
在垃圾收集代码中,如果继续保持对不再需要的对象的任何引用,则会认为内存泄露,从而阻止垃圾回收器回收它。如果无限期地保留不需要的对象,则会在垃圾收集代码中创建永久性泄漏。
答案 2 :(得分:3)
new/new[]/malloc
而不是释放它p = new int; p = new int[1];
new int[100];
或cout<<(*new string("hello"))<<endl;
答案 3 :(得分:2)
总是我最喜欢的,“非泄漏的内存泄漏”,你的程序正确地保留了指向已分配内存的指针,但是(无论出于什么原因)从来没有实际释放它们指向的内存:
// Maybe not technically a memory leak, but it might as well be one
static vector<const char *> strings;
void StoreTheString(const char * str)
{
strings.push_back(strdup(str));
}
这是令人讨厌的,因为内存泄漏检测器程序不会将其识别为内存泄漏(因为指针仍然可以访问),但是程序仍会耗尽内存直至崩溃。
即使在像Java这样的垃圾收集语言中也会出现这种问题。
答案 4 :(得分:1)
碎片可能是导致内存不足的问题之一。 经过长时间运行程序后,可能会导致内存碎片化。
答案 5 :(得分:1)
另一种情况是使用引用计数智能指针,如boost::shared_ptr
,通常被认为是“消除内存泄漏”,但是您创建了循环引用。
答案 6 :(得分:0)
我使用带有重载operator new和delete的Boehm垃圾收集器,它适用于任何使用它编译的类,但是对于std :: string和一些STL容器也是如此,即使变量是垃圾收集类的成员。在我意识到之前,有一些内存泄漏。值得庆幸的是,它提供了一个垃圾收集分配器。
我还记得一辆用Java编程的自动驾驶汽车,每20到40分钟坠毁一次。它收集了关于沿路上遇到的各种灌木丛和垃圾的物体检测信息,将它们订阅到某个队列,......并且从未将它们删除。
*:看看我在那里做了什么:D