内存泄漏-每个程序员的噩梦?

我正在使用C++编写一个游戏引擎,该引擎也支持Lua。

我的最大恐惧:内存泄漏。

并不是说我的游戏已经充斥着这些问题,我更担心在开发的后期、项目变得庞大和复杂的时候,这些问题会像蘑菇一样从地下冒出来。

我害怕这些问题,因为它们对我来说似乎非常难以发现,特别是在复杂的系统中。如果我的引擎即将完成,游戏正在运行,但内存正在被消耗,那么我该怎么办?我要从哪里开始搜索?

  • 我对内存泄漏的恐惧是否合理?
  • 如何找出内存泄漏的源头?
  • 现在有没有好的工具可以帮助找到内存泄漏的源头?

原文链接 https://stackoverflow.com/questions/4914184

点赞
stackoverflow用户252000
stackoverflow用户252000

将下面翻译成中文并且保留原本的 markdown 格式

你可以通过永远不使用裸指针来避免内存泄漏。如果你的代码中使用了裸指针,请进行重构。

2011-02-06 15:30:43
stackoverflow用户439777
stackoverflow用户439777

可以使用 Valgrind 工具来查找内存泄漏问题。

2011-02-06 15:35:07
stackoverflow用户346104
stackoverflow用户346104

一个被良好定义的“对象生命周期”模型是必要的。每次你使用“new”关键字时,你需要思考以下问题:

  1. 谁拥有这个堆对象?也就是谁负责维护这个指针并允许其他“客户端”引用它?

  2. 谁负责删除这个对象?通常是问题 #1,但不一定如此。

  3. 是否存在这个对象的任何客户端的生命周期比这个对象长?如果是这样,并且他们实际存储了这个堆指针,它将会引用不再“存在”的内存。你可能需要添加一些通知机制或重新设计你的“对象生命周期”模型。

很多时候你修复了内存泄漏,但接着遇到问题 #3。这就是为什么在写太多代码之前考虑好你的对象生命周期模型最好的原因。

2011-02-06 15:37:37
stackoverflow用户388182
stackoverflow用户388182

不必惊慌,但内存泄漏会损害程序的性能(因此要消除)。

  1. 不要害怕内存泄漏。想想它们的含义——未被删除且所有访问已被移除的内存(因此,在执行结束之前,系统不知道它可以重新分配该内存)。

  2. 手动找到可能的内存泄漏,通过检查对象并确保它们在正确的位置进行删除(仅此一次!否则,其他错误会出现)。 诸如[Valgrind](http://valgrind.org/)之类的工具可以帮助发现错误所在。

  3. 如前所述(我之前提到的),[Valgrind](http://valgrind.org/)是找到内存泄漏的好工具。 运行以下命令:

    valgrind --leak-check=full -v ./YOUR_EXECUTABLE

这将为您提供完整的泄漏检查和有关程序中内存使用方式的详细输出。

敬礼,

Dennis M.

2011-02-06 15:46:15
stackoverflow用户147877
stackoverflow用户147877

Raw pointers are only one potential cause of memory leaks.

即使使用诸如shared_ptr之类的智能指针,如果存在循环引用,仍有可能出现内存泄漏 - 解决此问题的方法是在某处使用weak_ptr来打破循环引用。使用智能指针并不能完全解决内存泄漏问题。

你也可以忘记在基类中使用虚析构函数,从而导致内存泄漏。

即使没有新分配的对象未被删除的问题,长时间运行的进程也可能因地址空间碎片化而增长(并显露出内存泄漏的情况)。

像valgrind这样的工具对于查找内存泄漏非常有用,但它们并不总能告诉您哪里需要进行修复(例如循环引用或持有智能指针的对象的情况)。

2011-02-06 16:10:34
stackoverflow用户523612
stackoverflow用户523612

我害怕内存泄露,这种担心是否合理?

如果你写的代码确实包含了内存泄露的问题,那么担心是完全合理的。

怎样才能找到内存泄漏的问题所在?

需要通过代码分析来找出。

现在有没有好的工具能帮助查找内存泄漏的源头呢?

是的,但仍然不容易。

好消息是,只要合理设计代码,这完全是不必要的。预防胜于治疗:处理内存泄漏的最佳策略是写出确保不会出现内存泄漏的代码。

2011-02-06 17:31:14
stackoverflow用户238884
stackoverflow用户238884

在冒着听起来像我可能是一个自负的混蛋的风险下,请考虑使用 1979 年之后开发的任何编程语言,它们不会有内存泄漏、堆栈破坏甚至内存管理等问题。(任何人都会比如 “我需要我的程序运行速度快” 的话,都可能从未听说过 Donald Knuth。)

2011-02-06 18:31:27
stackoverflow用户9611
stackoverflow用户9611

据我所知,Valgrid仅适用于Linux。

对于Windows,你有类似于BoundsCheckerPurify的工具。

如果你使用Visual Studio,C运行时库(CRT)也提供了一个非常简单和有用的工具,可以直接找出内存泄漏。请阅读关于_CrtDumpMemoryLeaks及其相关函数和宏的说明。

该工具基本上允许您在进程退出时获取带索引的内存泄漏转储,然后允许您在分配泄漏内存的时间设置断点,以确切地查明何时发生内存泄漏。这与大多数其他工具不同,其他工具只能提供事后分析,没有办法重现导致内存泄漏的事件。

从一开始就使用这些好工具可以让你相对放心,知道自己处于良好状态。

2011-02-06 22:05:42
stackoverflow用户72312
stackoverflow用户72312

有各种技术来跟踪内存泄漏。

最简单的方法是使用宏和特定的分配器来存储分配这部分内存的函数。这样,您可以跟踪每个分配并查看应该删除但未删除的部分。然后,您可以开始编写单元测试并断言内存已被释放。

如果您始终使用预编译容器,则无法使用此方法,因为所有分配都在容器中。然后您的选择是:

  • 在运行时使用线程本地值以识别子系统或类ID(在调试构建中),以便您的分配器可以检测谁正在分配内存。您甚至可以使用堆栈来分层地跟踪内存使用情况。
  • 如果您的编译器有足够的支持,则实际检索调用堆栈并将其存储。
  • 对于子系统,使用内存池,并测量其尺寸是否不成比例。 (这也是泄漏内存的一个(虽然较差的)解决方法,因为如果可能的话,您可以一次性释放整个池,从而释放泄漏的内存。)
  • 在Windows上,在调试版本下,有一些宏可以自动跟踪内存分配来自源代码的行。

可能还有更多选择。如果您的设计允许,测试和使用自定义全局new / delete覆盖(可以查询)应该是有用的。

另外,请参阅[Electronic Arts STL C ++论文](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html),了解有关在STL / C ++中支持适当的游戏开发所需做的内容的讨论。(它可能比您的引擎更加强大,但它肯定包含许多灵感和创新点。)

2011-02-06 22:20:46
stackoverflow用户107090
stackoverflow用户107090

至少对于 Lua 部分,您可以使用自己的内存分配器并跟踪所有分配和释放,从而发现任何内存泄漏。

2011-02-06 23:34:03
stackoverflow用户61505
stackoverflow用户61505

可以使用 Visual Leak Detector 来查找内存泄漏的位置,适用于 Visual C++ 2008/2010。

2011-03-05 12:57:21