内存泄漏是否有可接受的限制?
我刚刚开始在 C++ 中尝试 SDL,我认为定期检查内存泄漏可能是尽早养成的好习惯。
考虑到这一点,我一直通过 Valgrind 运行“Hello world”程序来捕获任何泄漏,尽管我已经删除了除最基本的 SDL_Init()
和 SDL_Quit( )
语句,Valgrind 仍然报告丢失了 120 个字节,并且仍然可以访问 77k。
我的问题是:内存泄漏是否有可接受的限制,或者我应该努力使我的所有代码完全无泄漏?
I've just started experimenting with SDL in C++, and I thought checking for memory leaks regularly may be a good habit to form early on.
With this in mind, I've been running my 'Hello world' programs through Valgrind to catch any leaks, and although I've removed everything except the most basic SDL_Init()
and SDL_Quit()
statements, Valgrind still reports 120 bytes lost and 77k still reachable.
My question is: Is there an acceptable limit for memory leaks, or should I strive to make all my code completely leak-free?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
请注意 Valgrind 不会在其测量中发现误报。
许多简单的内存分析器实现将丢失的内存标记为泄漏,但实际上并非如此。
也许可以阅读 有关 Purify 的维基百科文章 的外部链接部分中的一些论文。 我知道 Purify 附带的文档描述了几种在尝试检测内存泄漏时出现误报的场景,然后继续描述 Purify 用于解决这些问题的技术。
顺便说一句,我与 IBM 没有任何关系。 我刚刚广泛使用 Purify,并保证其有效性。
编辑:这是一篇优秀的介绍性文章,介绍了内存监控。 它是 Purify 特有的,但关于内存错误类型的讨论非常有趣。
HTH。
干杯,
罗布
Be careful that Valgrind isn't picking up false positives in its measurements.
Many naive implementations of memory analyzers flag lost memory as a leak when it isn't really.
Maybe have a read of some of the papers in the external links section of the Wikipedia article on Purify. I know that the documentation that comes with Purify describes several scenarios where you get false positives when trying to detect memory leaks and then goes on to describe the techniques Purify uses to get around the issues.
BTW I'm not affiliated with IBM in any way. I've just used Purify extensively and will vouch for its effectiveness.
Edit: Here's an excellent introductory article covering memory monitoring. It's Purify specific but the discussion on types of memory errors is very interesting.
HTH.
cheers,
Rob
您必须小心“内存泄漏”的定义。 第一次使用时分配一次并在程序退出时释放的东西有时会被泄漏检测器显示,因为它在第一次使用之前开始计数。 但这不是泄漏(尽管它可能是糟糕的设计,因为它可能是某种全局的)。
要查看给定的代码块是否泄漏,您可以合理地运行一次,然后清除泄漏检测器,然后再次运行它(这当然需要对泄漏检测器进行编程控制)。 每次运行程序时“泄漏”一次的事情通常并不重要。 每次执行时“泄露”的事情通常最终都会产生影响。
我很少发现在这个指标上达到零太困难,这相当于观察缓慢的内存使用情况而不是丢失的块。 我有一个库,它变得非常繁琐,有缓存和 UI 家具等等,我只是运行了我的测试套件三遍,并忽略了任何在三个块的倍数中没有发生的“泄漏”。 我仍然发现了所有或几乎所有真正的泄密事件,并在解决了容易实现的问题后分析了棘手的报告。 当然,为此目的使用测试套件的缺点是(1)您只能使用不需要新流程的部分,以及(2)您发现的大多数泄漏都是测试代码的错误,不是库代码...
You have to be careful with the definition of "memory leak". Something which is allocated once on first use, and freed on program exit, will sometimes be shown up by a leak-detector, because it started counting before that first use. But it's not a leak (although it may be bad design, since it may be some kind of global).
To see whether a given chunk of code leaks, you might reasonably run it once, then clear the leak-detector, then run it again (this of course requires programmatic control of the leak detector). Things which "leak" once per run of the program usually don't matter. Things which "leak" every time they're executed usually do matter eventually.
I've rarely found it too difficult to hit zero on this metric, which is equivalent to observing creeping memory usage as opposed to lost blocks. I had one library where it got so fiddly, with caches and UI furniture and whatnot, that I just ran my test suite three times over, and ignored any "leaks" which didn't occur in multiples of three blocks. I still caught all or almost all the real leaks, and analysed the tricky reports once I'd got the low-hanging fruit out of the way. Of course the weaknesses of using the test suite for this purpose are (1) you can only use the parts of it that don't require a new process, and (2) most of the leaks you find are the fault of the test code, not the library code...
在最好的情况下,(在我看来)内存泄漏(和其他粗心问题)是非常糟糕的编程。 在最坏的情况下,它会导致软件无法使用。
您应该首先避免引入它们,并运行您和其他人提到的工具来尝试检测它们。
避免草率的编程——已经有足够多的糟糕程序员了——世界不需要另一个。
编辑
我同意 - 许多工具都可以提供误报。
Living with memory leaks (and other careless issues) is, at its best, (in my opinion) very bad programming. At its worst it makes software unusable.
You should avoid introducing them in the first place and run the tools you and others have mentioned to try to detect them.
Avoid sloppy programming - there are enough bad programmers out there already - the world doesn't need another one.
EDIT
I agree - many tools can provide false positives.
如果您确实担心内存泄漏,则需要进行一些计算。
您需要测试您的应用程序大约一个小时,然后计算泄漏的内存。 这样,您就可以获得泄漏的内存字节/分钟值。
现在,您需要估计程序会话的平均长度。 例如,对于 notepad.exe,15 分钟对我来说听起来是一个不错的估计。
如果(平均会话长度)*(泄漏字节/分钟)> 0.3 *(进程通常占用的内存空间),那么您可能应该做更多的努力来减少内存泄漏。 我刚刚编了0.3,用常识来确定你可以接受的阈值。
请记住,成为一名程序员的一个重要方面是成为一名软件工程师,而工程通常就是从两个或多个糟糕的选项中选择最不最坏的选项。 当你需要衡量一个选择实际上有多糟糕时,数学总是很方便。
If you are really worried about memory leaking, you will need to do some calculations.
You need to test your application for like, an hour and then calculate the leaked memory. This way, you get a leaked memory bytes/minute value.
Now, you will need to estimate the average length of the session of your program. For example, for notepad.exe, 15 minutes sounds like a good estimation for me.
If (average session length)*(leaked bytes / minute) > 0.3 * (memory space normally occupied by your process), then you should probably do some more efforts to reduce memory leaks. I just made up 0.3, use common sense to determine your acceptable threshold.
Remember that an important aspect of being a programmer is being a Software Engineer, and very often Engineering is about choosing the least worst option from two or more bad options. Maths always comes handy when you need to measure how bad an option is actually.
大多数操作系统(包括Windows)都会在程序卸载时归还程序分配的所有内存。 这包括程序本身可能丢失的任何内存。
鉴于此,我通常的理论是,在启动期间泄漏内存是完全可以的,但在运行时泄漏内存就不行了。
因此,真正的问题不在于您是否泄漏任何内存,而在于您是否在程序运行时不断泄漏内存。 如果您使用您的程序一段时间,并且无论您做什么,丢失的字节数都保持在 120 字节而不是增加,那么我想说您已经做得很好了。 继续前行。
Most OSes (including Windows) will give back all of a program's allocated memory when the program is unloaded. This includes any memory which the program itself may have lost track of.
Given that, my usual theory is that it's perfectly fine to leak memory during startup, but not OK to do it during runtime.
So really the question isn't if you are leaking any memory, it is if you are continually leaking it during your program's runtime. If you use your program for a while, and no matter what you do it stays at 120 bytes lost rather than increasing, I'd say you have done great. Move on.
对于桌面应用程序来说,小的内存泄漏并不是真正的问题。 对于服务(服务器)来说,内存泄漏是不可接受的。
For a desktop application, small memory leaks are not a real problem. For services (servers) no memory leaks are acceptable.
这取决于您的应用程序。 一些泄漏可能是不可避免的(由于查找泄漏所需的时间与截止日期)。 只要您的应用程序可以按照您想要的时间运行,并且在这段时间内不会占用大量内存,那么就可以了。
It depends on your application. Some leaking may be unavoidable (due to the time needed to find the leak v.s. deadlines). As long as your application can run as long as you want, and not take an crazy amount of memory in that time it's probably fine.
看起来 SDL 开发人员确实不使用 Valgrind,但我基本上只关心丢失的那 120 个字节。
好吧,对于 Valgrind,“仍然可达的内存”通常并不是真正泄漏的内存,尤其是在这样一个简单的程序中。 我可以放心地打赌,SDL_Quit() 中基本上没有分配,因此“泄漏”只是 SDL_Init() 分配过一次的结构。
尝试添加有用的工作,看看这些数量是否会增加; 尝试制作一个有用工作的循环(例如创建和销毁某些 SDL 结构),并查看泄漏量是否随着迭代量的增加而增加。 在后一种情况下,您应该检查泄漏的堆栈跟踪并修复它们。
否则,那些 77k 泄漏算作“应该在程序结束时释放的内存,但它们依赖操作系统来释放它。
所以,实际上,我现在更担心这 120 字节,如果它们不是 false Valgrind 的误报通常很少是有意使用未初始化内存的情况(例如,因为它实际上是填充)。
It does look like SDL developers don't use Valgrind, but I basically only care about those 120 bytes lost.
Well, with Valgrind, "still reachable memory" is often not really leaked memory, especially in such a simple program. I can bet safely that there is basically no allocation in SDL_Quit(), so the "leaks" are just structures allocated once by SDL_Init().
Try adding useful work and seeing if those amounts increase; try making a loop of useful work (like creating and destroying some SDL structure) and see if the amount of leaks grows with the amount of iterations. In the latter case, you should check the stack traces of the leaks and fix them.
Otherwise, those 77k leaks count as "memory which should be freed at program end, but for which they rely on the OS to free it.
So, actually, I'm more worried right now by those 120 bytes, if they are not false positives, and they are usually few. False positives with Valgrind are mostly cases where usage of uninitialized memory is intended (for instance because it is actually padding).
根据 Rob Wells 对 Purify 的评论,下载并尝试其他一些工具。 我使用 BoundsChecker 和 AQTime,多年来在这两者中都看到了不同的误报。 请注意,内存泄漏也可能发生在第三方组件中,您可能希望将其从分析中排除。 从示例来看,MFC 在第一个视图版本中存在大量内存泄漏。
IMO,对于进入可能具有较长生命周期的代码库的任何代码,都应该跟踪内存泄漏。 如果您无法找到它们,至少请记下它们存在于相同代码的下一个用户中。
As per Rob Wells' comments on Purify, download and try out some of the other tools out there. I use BoundsChecker and AQTime, and have seen different false positives in both over the years. Note that the memory leak might also be in a third party component, which you may want to exclude from your analysis. From example, MFC had a number of memory leaks in the first view versions.
IMO, memory leaks should be tracked down for any code that is going into a code base that may have a long life. If you can't track them down, at least make a note that they exist for the next user of the same code.
Firstable 内存泄漏只有当它们随着时间的推移而增长时才是一个严重的问题,否则应用程序从外部看起来只是有点大(显然这里也有一个限制,因此“严重”)。
当泄漏随着时间的推移而扩大时,您可能会遇到麻烦。 麻烦多少取决于具体情况。 如果您知道内存的去向,并且可以确保始终有足够的内存来运行该程序以及该机器上的其他所有内容,那么您仍然可以。
但是,如果您不知道内存在哪里,我就不会发布该程序并继续挖掘。
Firstable memory leaks are only a serious problem when they grow with time, otherwise the app just looks a little bigger from the outside (obviously there's a limit here too, hence the 'serious').
When you have a leak that grows with time you might be in trouble. How much trouble depends on the circumstances though. If you know where the memory is going and can make sure that you'll always have enough memory to run the program and everything else on that machine you are still somewhat fine.
If you don't know where the memory is going however, i wouldn't ship the program and keep digging.
特别是对于 Linux 上的 SDL,底层 X windows 库似乎存在一些泄漏。 对于这些你无能为力(除非你想尝试修复库本身,这可能不适合胆小的人)。
您可以使用 valgrind 的抑制机制(请参阅 valgrind 手册页中的 --suppressions 和 --gen-suppressions)来告诉它不要用这些错误来打扰您。
一般来说,我们确实必须对第三方库宽容一点; 虽然我们绝对不应该接受我们自己的代码中的内存泄漏,并且内存泄漏的存在应该是在替代第三方库之间进行选择时的一个因素,但有时我们别无选择,只能忽略它们(尽管报告它们可能是一个好主意给库维护者)。
With SDL on Linux in particular, there seem to be some leaking in the underlying X windows library. There's nothing much you can do about those (unless you want to try to fix the library itself, which is probably not for the faint hearted).
You can use valgrind's suppression mechanism (see --suppressions and --gen-suppressions in the valgrind man page) to tell it not to bother you with these errors.
In general we do have to be a little more lenient with third party libraries; while we should absolutely not accept memory leaks in our own code, and the presence of memory leaks should be a factor when choosing between alternative third party libraries, sometimes there's no choice but to ignore them (though it may be a good idea to report them to the library maintainer).