不同的内存泄漏方式
Different ways of leaking memory
内存泄漏的基本概念是代码执行过程中新的/删除操作不匹配,这可能是由于错误的编码实践造成的,也可能是在跳过删除操作时出现错误的情况下造成的。
但最近,我在一次采访中被问到一个问题,关于记忆泄露的其他方式。我没有答案。这是什么?
常见的动态内存问题有:
- 使用
new
进行动态内存分配,而不使用delete
进行解除分配 - 用
new[]
动态分配内存,用delete
解除分配内存 - 动态内存分配CCD_ 5并将其与CCD_ 6解除分配
- 动态内存分配CCD_ 7并用CCD_
除了内存泄漏/内存损坏外,最后三种情况还会导致可怕的未定义行为。
我还记得其他一些可能导致内存泄漏的场景:
- 如果指向动态分配内存区域的指针在被释放之前被重新分配了一个新值,则会导致悬挂指针和内存泄漏
代码示例:
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容器只有在所包含的对象不是指针类型时才拥有删除该对象的所有权
在删除容器本身之前,必须显式地遍历容器并删除每个包含的类型。不这样做会导致内存泄漏
这里就是这样一个场景的例子。
-非虚拟基类析构函数问题
删除指向基类的指针,该指针指向堆上派生类的任何动态分配对象。这将导致未定义的行为。
一个代码示例:
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(){}
-在void
指针上调用delete
代码示例:
void doSomething( void * p )
{
//do something interesting
if(p)
delete p;
}
int main()
{
A* p = new A();
doSomething(p);
return 0;
}
如上例所示,在void
指针上调用delete
将导致内存泄漏和Undefined Behavior。
作为一个面试问题,面试官可能一直在寻找比教科书新/删除不匹配更广阔的视角。
任何持续超过最后一点的内存都可以被视为"泄漏"。通过在代码中进一步删除,这些内存最终可能会被手动释放,从而使这些泄漏成为临时性的,而不是使用不匹配的新/delete运算符时遇到的永久性泄漏。然而,在"泄漏"持续的时间内,净效果是相同的。您正在减少程序其他部分的可用资源(内存)量。
在垃圾收集代码中,如果继续保留对不再需要的对象的任何引用,则认为内存泄漏,从而阻止垃圾收集器回收内存。如果无限期保留不需要的对象,则在垃圾收集的代码中创建了永久泄漏。
- 使用分配内存
new/new[]/malloc
并且不释放它 - 将内存分配给某个指针并意外覆盖,例如
p = new int; p = new int[1];
- 在空中分配内存。即
new int[100];
或cout<<(*new string("hello"))<<endl;
我最喜欢的是"无泄漏内存泄漏",在这种情况下,程序正确地保留了指向已分配内存的指针,但(无论出于何种原因)从未真正腾出时间来释放它们指向的内存:
// 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这样的垃圾收集语言中。
另一种情况是使用引用计数智能指针,如boost::shared_ptr
,通常认为它可以"消除内存泄漏",但您可以创建循环引用。
如何使用shared_ptr避免内存泄漏?
碎片可能是导致内存不足的问题之一。长时间运行程序后,可能会导致内存碎片。
我使用带有重载运算符new和delete的Boehm垃圾收集器,它非常适用于使用它编译的任何类,但在std::string和一些STL容器中也会失败,即使变量是垃圾收集类的成员。在我意识到之前有一些内存泄漏。谢天谢地,它提供了一个垃圾回收分配器。
我还记得一辆用Java编程的自动驾驶汽车,但每20到40分钟就会坠毁一次。它收集了路上遇到的各种灌木丛和垃圾的物体检测信息,并为它们订阅了一些队列。。。并且从未移除它们。
*:看看我在那里做了什么:D
- valgrind-hellgrind与泄漏检查的结果不同
- 如何在c++中为模板函数实例创建快捷方式
- 在c代码之间共享数据的最佳方式
- 在C++中将函数压缩为两种方式
- 从构造函数抛出异常时如何克服内存泄漏
- 以螺旋方式打印矩阵的程序.(工作不好)
- malloc() 可能出现内存泄漏
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- 创建引用向量的优雅方式
- 这个极客对极客的trie实现是否存在内存泄漏问题
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 不同/较旧的处理器运行c++代码的方式是否不同
- 从嵌套在std::映射中的std::列表中删除元素的最佳方式
- 尽管遵循了规则,内存泄漏在哪里
- 为什么调用堆栈数组会导致内存泄漏
- 如果条件为TRUE(最佳方式?),则在do while循环中后置增量
- 如何以可移植的方式在C++中自动检测内存泄漏
- 以多态方式使用派生类的std::vector成员的复制赋值会导致内存泄漏
- 不同的内存泄漏方式