C++ 内存泄漏好吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/273209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are memory leaks ever ok?
提问by Imbue
Is it ever acceptable to have a memory leakin your C or C++ application?
在您的 C 或 C++ 应用程序中存在内存泄漏是否可以接受?
What if you allocate some memory and use it until the very last line of code in your application (for example, a global object's destructor)? As long as the memory consumption doesn't grow over time, is it OK to trust the OS to free your memory for you when your application terminates (on Windows, Mac, and Linux)? Would you even consider this a real memory leak if the memory was being used continuously until it was freed by the OS.
如果您分配一些内存并使用它直到应用程序中的最后一行代码(例如,全局对象的析构函数)怎么办?只要内存消耗不随时间增长,是否可以信任操作系统在应用程序终止时为您释放内存(在 Windows、Mac 和 Linux 上)?如果内存一直被使用直到被操作系统释放,你甚至会认为这是一个真正的内存泄漏。
What if a third party library forced this situation on you? Would refuse to use that third party library no matter how great it otherwise might be?
如果第三方图书馆将这种情况强加给您怎么办?会拒绝使用该第三方库,无论它有多好?
I only see one practical disadvantage, and that is that these benign leaks will show up with memory leak detection tools as false positives.
我只看到一个实际的缺点,那就是这些良性泄漏会在内存泄漏检测工具中显示为误报。
回答by JohnMcG
No.
不。
As professionals, the question we should not be asking ourselves is, "Is it ever OK to do this?" but rather "Is there ever a goodreason to do this?" And "hunting down that memory leak is a pain" isn't a good reason.
作为专业人士,我们不应该问自己的问题是:“这样做可以吗?” 而是“这样做有充分的理由吗?” 并且“追查内存泄漏是一种痛苦”并不是一个很好的理由。
I like to keep things simple. And the simple rule is that my program should have no memory leaks.
我喜欢保持简单。简单的规则是我的程序应该没有内存泄漏。
That makes my life simple, too. If I detect a memory leak, I eliminate it, rather than run through some elaborate decision tree structure to determine whether it's an "acceptable" memory leak.
这也让我的生活变得简单。如果我检测到内存泄漏,我会消除它,而不是通过一些复杂的决策树结构来确定它是否是“可接受的”内存泄漏。
It's similar to compiler warnings – will the warning be fatal to my particular application? Maybe not.
它类似于编译器警告——警告对我的特定应用程序来说是致命的吗?也许不吧。
But it's ultimately a matter of professional discipline. Tolerating compiler warnings and tolerating memory leaks is a bad habit that will ultimately bite me in the rear.
但这归根结底是专业纪律问题。容忍编译器警告和容忍内存泄漏是一个坏习惯,最终会在后面咬我。
To take things to an extreme, would it ever be acceptable for a surgeon to leave some piece of operating equipment inside a patient?
将事情推向极端,外科医生将一些手术设备留在患者体内是否可以接受?
Although it is possible that a circumstance could arise where the cost/risk of removing that piece of equipment exceeds the cost/risk of leaving it in, and there could be circumstances where it was harmless, if I saw this question posted on SurgeonOverflow.com and saw any answer other than "no," it would seriously undermine my confidence in the medical profession.
尽管可能会出现移除该设备的成本/风险超过将其留在其中的成本/风险的情况,并且可能存在无害的情况,如果我在 SurgeonOverflow.com 上看到这个问题看到除了“不”之外的任何答案,都会严重削弱我对医学界的信心。
–
——
If a third party library forced this situation on me, it would lead me to seriously suspect the overall quality of the library in question. It would be as if I test drove a car and found a couple loose washers and nuts in one of the cupholders – it may not be a big deal in itself, but it portrays a lack of commitment to quality, so I would consider alternatives.
如果第三方图书馆把这种情况强加给我,我会严重怀疑这个图书馆的整体质量。就好像我试驾了一辆车,在其中一个杯架上发现了几个松动的垫圈和螺母——这本身可能没什么大不了的,但它表现出对质量的缺乏承诺,所以我会考虑替代品。
回答by Jim C
I don't consider it to be a memory leak unless the amount of memory being "used" keeps growing. Having some unreleased memory, while not ideal, is not a big problem unless the amount of memory required keeps growing.
除非“使用”的内存量不断增长,否则我不认为这是内存泄漏。有一些未释放的内存虽然不理想,但不是大问题,除非所需的内存量不断增长。
回答by Charlie Martin
Let's get our definitions correct, first. A memory leakis when memory is dynamically allocated, eg with malloc()
, and all references to the memory are lost without the corresponding free. An easy way to make one is like this:
首先,让我们正确定义我们的定义。内存泄漏是指动态分配内存时,例如使用malloc()
,并且所有对内存的引用都丢失而没有相应的空闲。一种简单的制作方法是这样的:
#define BLK ((size_t)1024)
while(1){
void * vp = malloc(BLK);
}
Note that every time around the while(1) loop, 1024 (+overhead) bytes are allocated, and the new address assigned to vp; there's no remaining pointer to the previous malloc'ed blocks. This program is guaranteed to run until the heap runs out, and there's no way to recover any of the malloc'ed memory. Memory is "leaking" out of the heap, never to be seen again.
请注意,每次在 while(1) 循环中,都会分配 1024 (+overhead) 个字节,并将新地址分配给 vp;没有剩余的指向前一个 malloc 块的指针。这个程序保证一直运行到堆用完为止,并且没有办法恢复任何 malloc 的内存。内存从堆中“泄漏”出来,再也看不到了。
What you're describing, though, sound like
不过,你所描述的听起来像
int main(){
void * vp = malloc(LOTS);
// Go do something useful
return 0;
}
You allocate the memory, work with it until the program terminates. This is nota memory leak; it doesn't impair the program, and all the memory will be scavenged up automagically when the program terminates.
您分配内存,使用它直到程序终止。这不是内存泄漏;它不会损害程序,当程序终止时,所有内存都会自动清理。
Generally, you should avoid memory leaks. First, because like altitude above you and fuel back at the hangar, memory that has leaked and can't be recovered is useless; second, it's a lot easier to code correctly, not leaking memory, at the start than it is to find a memory leak later.
通常,您应该避免内存泄漏。首先,因为就像你上面的高度和机库里的燃料一样,已经泄漏且无法恢复的内存是无用的;其次,在开始时正确编码而不是泄漏内存比以后发现内存泄漏要容易得多。
回答by vfilby
In theory no, in practise it depends.
理论上不,在实践中它取决于。
It really depends on how much data the program is working on, how often the program is run and whether or not it is running constantly.
这实际上取决于程序正在处理多少数据,程序运行的频率以及它是否一直在运行。
If I have a quick program that reads a small amount of data makes a calculation and exits, a small memory leak will never be noticed. Because the program is not running for very long and only uses a small amount of memory, the leak will be small and freed when the program exists.
如果我有一个读取少量数据的快速程序进行计算并退出,则永远不会注意到小的内存泄漏。因为程序运行时间不是很长,只使用了少量内存,所以当程序存在时,泄漏会很小并被释放。
On the other hand if I have a program that processes millions of records and runs for a long time, a small memory leak might bring down the machine given enough time.
另一方面,如果我有一个处理数百万条记录并运行很长时间的程序,如果有足够的时间,一个小的内存泄漏可能会导致机器宕机。
As for third party libraries that have leaks, if they cause a problem either fix the library or find a better alternative. If it doesn't cause a problem, does it really matter?
至于有泄漏的第三方库,如果它们导致问题,要么修复库,要么找到更好的替代方案。如果它不会引起问题,那真的很重要吗?
回答by Artelius
Many people seem to be under the impression that once you free memory, it's instantly returned to the operating system and can be used by other programs.
很多人似乎有这样的印象,一旦你释放内存,它会立即返回到操作系统并且可以被其他程序使用。
This isn't true. Operating systems commonly manage memory in 4KiB pages. malloc
and other sorts of memory management get pages from the OS and sub-manage them as they see fit. It's quite likely that free()
will notreturn pages to the operating system, under the assumption that your program will malloc more memory later.
这不是真的。操作系统通常以 4KiB 页面管理内存。malloc
和其他类型的内存管理从操作系统获取页面并在他们认为合适的时候对它们进行子管理。这很可能free()
将不会返回页面操作系统,假设你的程序将在以后的malloc更多的内存下。
I'm not saying that free()
never returns memory to the operating system. It can happen, particularly if you are freeing large stretches of memory. But there's no guarantee.
我并不是说free()
永远不会将内存返回给操作系统。它可能会发生,特别是当您释放大量内存时。但没有保证。
The important fact:If you don't free memory that you no longer need, further mallocs are guaranteed to consume even morememory. But if you free first, malloc might re-use the freed memory instead.
重要的事实:如果你不释放不再需要的内存,进一步的 malloc 肯定会消耗更多的内存。但是如果你先释放,malloc 可能会重新使用释放的内存。
What does this mean in practice? It means that if you know your program isn't going to require any more memory from now on (for instance it's in the cleanup phase), freeing memory is not so important. However if the program might allocate more memory later, you should avoid memory leaks - particularly ones that can occur repeatedly.
这在实践中意味着什么?这意味着如果你知道你的程序从现在开始不需要更多内存(例如它处于清理阶段),释放内存就不是那么重要了。但是,如果程序稍后可能会分配更多内存,则应避免内存泄漏 - 特别是可能重复发生的内存泄漏。
Also see this commentfor more details about why freeing memory just before termination is bad.
另请参阅此评论以了解有关为什么在终止之前释放内存不好的更多详细信息。
A commenter didn't seem to understand that calling free()
does not automatically allow other programs to use the freed memory. But that's the entire point of this answer!
评论者似乎不明白调用free()
不会自动允许其他程序使用释放的内存。但这就是这个答案的全部意义!
So, to convince people, I will demonstrate an example where free() does very little good. To make the math easy to follow, I will pretend that the OS manages memory in 4000 byte pages.
因此,为了说服人们,我将演示一个示例,其中 free() 的作用很小。为了使数学易于理解,我将假设操作系统以 4000 字节的页面管理内存。
Suppose you allocate ten thousand 100-byte blocks (for simplicity I'll ignore the extra memory that would be required to manage these allocations). This consumes 1MB, or 250 pages. If you then free 9000 of these blocks at random, you're left with just 1000 blocks - but they're scattered all over the place. Statistically, about 5 of the pages will be empty. The other 245 will each have at least one allocated block in them. That amounts to 980KB of memory, that cannot possibly be reclaimed by the operating system - even though you now only have 100KB allocated!
假设您分配了一万个 100 字节的块(为简单起见,我将忽略管理这些分配所需的额外内存)。这会占用 1MB 或 250 页。如果您随后随机释放 9000 个这些块,则只剩下 1000 个块 - 但它们散落在各处。据统计,大约有 5 个页面是空的。其他 245 个将每个都有至少一个已分配的块。这相当于 980KB 的内存,操作系统不可能回收它——即使您现在只分配了 100KB!
On the other hand, you can now malloc() 9000 more blocks without increasing the amount of memory your program is tying up.
另一方面,您现在可以在不增加程序占用的内存量的情况下 malloc() 9000 个以上的块。
Even when free()
could technicallyreturn memory to the OS, it may not do so. free()
needs to achieve a balance between operating quickly and saving memory. And besides, a program that has already allocated a lot of memory and then freed it is likely to do so again. A web server needs to handle request after request after request - it makes sense to keep some "slack" memory available so you don't need to ask the OS for memory all the time.
即使技术上free()
可以将内存返回给操作系统,它也可能不会这样做。需要在快速操作和节省内存之间取得平衡。此外,已经分配了大量内存然后释放它的程序很可能会再次这样做。Web 服务器需要一个接一个的处理请求 - 保持一些“空闲”内存可用是有意义的,这样你就不需要一直向操作系统询问内存。free()
回答by kasperjj
There is nothing conceptually wrong with having the os clean up after the application is run.
在应用程序运行后清理操作系统在概念上没有任何问题。
It really depends on the application and how it will be run. Continually occurring leaks in an application that needs to run for weeks has to be taken care of, but a small tool that calculates a result without too high of a memory need should not be a problem.
这实际上取决于应用程序及其运行方式。在需要运行数周的应用程序中不断发生的泄漏必须得到处理,但计算结果的小工具不需要太高的内存应该不成问题。
There is a reason why many scripting language do not garbage collect cyclical references… for their usage patterns, it's not an actual problem and would thus be as much of a waste of resources as the wasted memory.
许多脚本语言不垃圾收集循环引用是有原因的……对于它们的使用模式,这不是一个实际问题,因此与浪费的内存一样浪费资源。
回答by Jason L
I believe the answer is no, never allow a memory leak, and I have a few reasons which I haven't seen explicitly stated. There are great technical answers here but I think the real answer hinges on more social/human reasons.
我相信答案是否定的,绝不允许内存泄漏,并且我有一些我没有看到明确说明的原因。这里有很好的技术答案,但我认为真正的答案取决于更多的社会/人类原因。
(First, note that as others mentioned, a true leak is when your program, at any point, loses track of memory resources that it has allocated. In C, this happens when you malloc()
to a pointer and let that pointer leave scope without doing a free()
first.)
(首先,请注意,正如其他人提到的,真正的泄漏是当您的程序在任何时候都无法跟踪它已分配的内存资源时。在 C 中,当您malloc()
指向一个指针并让该指针离开作用域而不执行任何操作时,就会发生这种情况free()
第一的。)
The important crux of your decision here is habit.When you code in a language that uses pointers, you're going to use pointers a lot. And pointers are dangerous; they're the easiest way to add all manner of severe problems to your code.
在这里做出决定的关键是习惯。当您使用使用指针的语言进行编码时,您将大量使用指针。指针是危险的;它们是将各种严重问题添加到代码中的最简单方法。
When you're coding, sometimes you're going to be on the ball and sometimes you're going to be tired or mad or worried. During those somewhat distracted times, you're coding more on autopilot. The autopilot effect doesn't differentiate between one-off code and a module in a larger project. During those times, the habits you establish are what will end up in your code base.
当您编码时,有时您会很忙,有时您会感到疲倦、生气或担心。在那些有点分心的时间里,你在自动驾驶仪上编码更多。自动驾驶效应不会区分一次性代码和更大项目中的模块。在那个时候,你建立的习惯最终会出现在你的代码库中。
So no, never allow memory leaks for the same reason that you should still check your blind spots when changing lanes even if you're the only car on the road at the moment. During times when your active brain is distracted, good habits are all that can save you from disastrous missteps.
所以不,永远不要因为同样的原因而允许内存泄漏,即使你是目前路上唯一的汽车,你仍然应该在变换车道时检查你的盲点。在您活跃的大脑分心的时候,只有良好的习惯才能避免灾难性的失误。
Beyond the "habit" issue, pointers are complex and often require a lot of brain power to track mentally. It's best to not "muddy the water" when it comes to your usage of pointers, especially when you're new to programming.
除了“习惯”问题,指针很复杂,通常需要大量的脑力来进行心理跟踪。在使用指针时,最好不要“搅浑水”,尤其是当您不熟悉编程时。
There's a more social aspect too. By proper use of malloc()
and free()
, anyone who looks at your code will be at ease; you're managing your resources. If you don't, however, they'll immediately suspect a problem.
还有一个更多的社会方面。通过正确使用malloc()
and free()
,任何查看您代码的人都会感到轻松;您正在管理您的资源。但是,如果您不这样做,他们会立即怀疑有问题。
Maybe you've worked out that the memory leak doesn't hurt anything in this context, but every maintainer of your code will have to work that out in his head too when he reads that piece of code.By using free()
you remove the need to even consider the issue.
也许您已经发现内存泄漏在这种情况下不会造成任何伤害,但是您的代码的每个维护者在阅读那段代码时也必须在头脑中解决这个问题。通过使用,free()
您甚至无需考虑这个问题。
Finally, programming is writing a mental model of a process to an unambiguous language so that a person and a computer can perfectly understand said process. A vital part of good programming practice is never introducing unnecessary ambiguity.
最后,编程是将一个过程的心智模型写成一种明确的语言,以便人和计算机可以完全理解该过程。良好的编程实践的一个重要部分是永远不要引入不必要的歧义。
Smart programming is flexible and generic. Bad programming is ambiguous.
智能编程是灵活和通用的。糟糕的编程是模棱两可的。
回答by R.. GitHub STOP HELPING ICE
I'm going to give the unpopular but practical answer that it's always wrong to free memory unless doing so will reduce the memory usage of your program. For instance a program that makes a single allocation or series of allocations to load the dataset it will use for its entire lifetime has no need to free anything. In the more common case of a large program with very dynamic memory requirements (think of a web browser), you should obviously free memory you're no longer using as soon as you can (for instance closing a tab/document/etc.), but there's no reason to free anything when the user selects clicks "exit", and doing so is actually harmful to the user experience.
我将给出一个不受欢迎但实用的答案,即释放内存总是错误的,除非这样做会减少程序的内存使用量。例如,进行单个分配或一系列分配以加载将在其整个生命周期中使用的数据集的程序不需要释放任何内容。在具有非常动态内存要求的大型程序的更常见情况下(想想网络浏览器),您显然应该尽快释放不再使用的内存(例如关闭选项卡/文档/等) ,但是没有理由在用户选择点击“退出”时释放任何东西,这样做实际上对用户体验有害。
Why? Freeing memory requires touching memory. Even if your system's malloc implementation happens not to store metadata adjacent to the allocated memory blocks, you're likely going to be walking recursive structures just to find all the pointers you need to free.
为什么?释放内存需要接触内存。即使您的系统的 malloc 实现碰巧不存储与分配的内存块相邻的元数据,您也可能会遍历递归结构,只是为了找到您需要释放的所有指针。
Now, suppose your program has worked with a large volume of data, but hasn't touched most of it for a while (again, web browser is a great example). If the user is running a lot of apps, a good portion of that data has likely been swapped to disk. If you just exit(0) or return from main, it exits instantly. Great user experience. If you go to the trouble of trying to free everything, you may spend 5 seconds or more swapping all the data back in, only to throw it away immediately after that. Waste of user's time. Waste of laptop's battery life. Waste of wear on the hard disk.
现在,假设您的程序处理了大量数据,但有一段时间没有触及其中的大部分数据(同样,Web 浏览器是一个很好的例子)。如果用户正在运行大量应用程序,则该数据的很大一部分可能已交换到磁盘。如果您只是退出(0)或从主返回,它会立即退出。很棒的用户体验。如果您尝试释放所有内容,那么您可能会花费 5 秒或更长时间将所有数据换回,然后立即将其丢弃。浪费用户的时间。浪费笔记本电脑的电池寿命。浪费在硬盘上的磨损。
This is not just theoretical. Whenever I find myself with too many apps loaded and the disk starts thrashing, I don't even consider clicking "exit". I get to a terminal as fast as I can and type killall -9 ... because I know "exit" will just make it worse.
这不仅仅是理论上的。每当我发现自己加载了太多应用程序并且磁盘开始抖动时,我什至不会考虑单击“退出”。我尽可能快地到达终端并输入 killall -9 ......因为我知道“退出”只会让情况变得更糟。
回答by Cervo
I think in your situation the answer may be that it's okay. But you definitely need to document that the memory leak is a conscious decision. You don't want a maintenance programmer to come along, slap your code inside a function, and call it a million times. So if you make the decision that a leak is okay you need to document it (IN BIG LETTERS) for whoever may have to work on the program in the future.
我认为在你的情况下,答案可能是没关系。但是您绝对需要记录内存泄漏是一个有意识的决定。您不希望维护程序员出现,将您的代码放入一个函数中,然后调用它一百万次。因此,如果您决定泄漏没有问题,您需要为将来可能需要在该程序上工作的任何人记录(用大写字母)。
If this is a third party library you may be trapped. But definitely document that this leak occurs.
如果这是第三方库,您可能会被困。但一定要记录发生这种泄漏。
But basically if the memory leak is a known quantity like a 512 KB buffer or something then it is a non issue. If the memory leak keeps growing like every time you call a library call your memory increases by 512KB and is not freed, then you may have a problem. If you document it and control the number of times the call is executed it may be manageable. But then you really need documentation because while 512 isn't much, 512 over a million calls is a lot.
但基本上,如果内存泄漏是一个已知数量,如 512 KB 缓冲区或其他东西,那么这不是问题。如果内存泄漏不断增长,就像每次调用库调用一样,你的内存增加了 512KB 并且没有被释放,那么你可能有问题。如果你记录它并控制调用执行的次数,它可能是可以管理的。但是你真的需要文档,因为虽然 512 并不多,但 512 超过一百万次调用就很多了。
Also you need to check your operating system documentation. If this was an embedded device there may be operating systems that don't free all the memory from a program that exits. I'm not sure, maybe this isn't true. But it is worth looking into.
您还需要检查您的操作系统文档。如果这是嵌入式设备,则可能有操作系统不会从退出的程序中释放所有内存。我不确定,也许这不是真的。但值得研究。
回答by pearcewg
I'm sure that someone can come up with a reason to say Yes, but it won't be me. Instead of saying no, I'm going to say that this shouldn't be a yes/no question. There are ways to manage or contain memory leaks, and many systems have them.
我敢肯定有人会想出一个理由说“是”,但不会是我。我不是说不,而是说这不应该是一个是/否的问题。有很多方法可以管理或控制内存泄漏,而且许多系统都有。
There are NASA systems on devices that leave the earth that plan for this. The systems will automatically reboot every so often so that memory leaks will not become fatal to the overall operation. Just an example of containment.
离开地球的设备上有 NASA 系统为此计划。系统会每隔一段时间自动重新启动,这样内存泄漏就不会对整体操作造成致命影响。只是一个遏制的例子。