Stackoverflow热门问题(六)-不释放malloc申请的空间到底会发生什么?

stackoverflow热门问题目录

不释放malloc申请的空间到底会发生什么?

  • Scott asked:
    • 有个问题困扰我很久了。
    • 在学校的时候我们都被要求(至少我是这样)释放每个被分配的指针。但我有点疑惑,如果不释放内存的话又能造成多少损失?在一些很明显的情况中,例如循环里的malloc或者线程执行的一部分,的确需要释放空间以防内存泄漏。但如果是我接下来提到的两个例子呢:
    • 首先,有一个类似这样的代码:
    • int main(){
    • char *a = malloc(1024);
    • /* Do some arbitrary stuff with 'a' (no alloc functions) */ //(随意对a做些操作但不使用任何分配内存的函数)
    • return 0;
    • }
    • 结果会如何?在我想来这个程序终止,然后堆空间被释放,所以即便不调用free函数也不会造成损失(我知道使用free函数对于正常终止、可维护性以及一个好习惯的重要性)。我这样的想法正确吗?
    • 第二,假设我有一个类似shell的程序。用户能够使用诸如aaa = 123的方式声明变量,并且为了后续方便使用,它们会以动态数据结构的方式存储。很明显的这会调用*alloc函数(例如哈希表,链表等数据结构)。对于这类程序,调用malloc后然后释放这些空间根本没用,因为这些变量将作用于整个程序执行期间,就我看来,还没有一个合适的方法去管理这些静态空间。在程序结束的时候才释放被分配的内存算是一个糟糕的设计吗?如果是的话,有其他实现方式吗?
      • 译者注:Windows的CMD就是一个shell。
  • Answers:
    • Paul Tomblin – vote: 403
      • 对于绝大多数现代操作系统来说,程序占用的内存会在结束后完全释放。唯一我能想到的例外是Palm OS,它的静态存储与运行时内存几乎一模一样,所以我猜不释放内存的话可能会让程序占据更多空间。
        • 译者注:最后这句话总感觉怪怪的。
      • 所以一般来说,不会有太大问题,除了运行时占用的空间比你实际需要的空间更多外,但这也只是因为你想为这个可能被使用的变量保持内存空间而造成的。
      • 不过,更好的方式是将不再需要的变量内存立即释放,并且在程序终止前释放所有内存。这更像一个练习,练习对内存的使用以及其判断释放时机的能力。如果你不保持追踪这些变化,就可能会造成内存泄漏。
      • 在程序结束时因文件未关闭而造成的问题有多种,如缓冲区的数据没有被清除并输出,又或是临时文件没有被删除。对于数据库的句柄来说,则是完成事务提交后才能正常结束。同样的,如果你使用类似C++或Objective C这类面向对象语言,当结束时没有释放对象会使得垃圾回收机制不被正常调用,其持有的资源也不会被清理。
        • 译者注:
          • get flushed: 应该是指缓冲区的flush操作,大致是清空缓冲区并输出其内容。
          • transactions: 数据库的事务,事务是一种原子操作,原子操作表示这个操作无法中断(但出错会回滚到事务开始前),是最小操作单元。
    • compie – vote: 116
      • 你的观点没有问题,你假设的例子的确不会有造成任何损失(至少现代操作系统上是这样的)。所有被分配的内存都将在程序结束被操作系统恢复。
      • Source: Allocation and GC Myths (PostScript alert!)
        • 分配误区4:无垃圾回收机制的程序总是需要回收所有它分配的内存。
          • 译者注:Myth除了神话这个意思外,还有误区的意思,当我知道的时候不由自主咂吧了一下嘴。
        • 事实:在频繁执行的代码中忽略释放内存的操作会引发内存泄漏,且这种泄漏造成的危害也难以接受。不过,直到程序退出才释放内存在性能上的表现通常更佳,因为不使用free函数的话,malloc的使用会更加便利。
          • 译者注:原文的意思表达/分隔符/首字母有够少见的。
        • 大多情况下,在程序结束前才回收内存毫无意义,因为操作系统会在结束后回收它们。并且,这种释放操作会涉及到无用对象的废弃页面,而操作系统不会。
          • 译者注:最后一句的free will touch and page in the dead objects,我不是很理解,我猜可能是说这些dead objects处于操作系统中某一page,而这个页面因为太久没调用,现在不在内存里面,如果要touch这个objects,就需要把这个废弃页面从硬盘或是其它地方调入内存,又因为马上就要结束程序了,这个操作很明显是多余且浪费性能的。
        • 结论:小心这些对分配计数的“内存泄漏探测者”,有的”泄漏”还是不错的!
      • 也就是说,你的确应该避免所有内存泄漏!
      • 第二个问题:你的设计没错。如果你需要存储些东西直到这个应用结束,用动态内存分配来做是没问题的。如果你不直到待分配内存空间的大小,那自然不能用静态内存分配。
    • Trevor Boyd Smith – vote: 62
      • === 校对与复用 ===
      • 如果你不去释放对象,你的代码就必须在其因进程终止而释放内存前能安全运行。即那些小型的一次性项目或者“废弃”[1]项目,那些你知道程序会在什么时候终止的项目。
      • 如果你的确去释放了所有动态分配的内存,那么未来的校对会更加顺利,并且还能将其使用在一个大项目中。
      • [1] 关于“废弃”项目。使用在“废弃”项目的代码有时并没有真正被废弃,十年后你可能发现它还在工作。
      • 我听说个一个故事,有些人为了娱乐而写了些让它硬件更高效的代码。他说“仅仅只是兴趣,不怎么专业”。几年后仍然有很多人在用它因兴趣开发的代码。

What REALLY happens when you don’t free after malloc?

  • Scott asked:
    • This has been something that has bothered me for ages now.
      • 有个问题困扰我很久了。
    • We are all taught in school (at least, I was) that you MUST free every pointer that is allocated. I’m a bit curious, though, about the real cost of not freeing memory. In some obvious cases, like when malloc is called inside a loop or part of a thread execution, it’s very important to free so there are no memory leaks. But consider the following two examples:
      • 在学校的时候我们都被要求(至少我是这样)释放每个被分配的指针。但我有点疑惑,如果不释放内存的话又能造成多少损失?在一些很明显的情况中,例如循环里的malloc或者线程执行的一部分,的确需要释放空间以防内存泄漏。但如果是我接下来提到的两个例子呢:
    • First, if I have code that’s something like this:
      • 首先,有一个类似这样的代码:
    • int main(){
    • char *a = malloc(1024);
    • /* Do some arbitrary stuff with 'a' (no alloc functions) */ //(随意对a做些操作但不使用任何分配内存的函数)
    • return 0;
    • }
    • What’s the real result here? My thinking is that the process dies and then the heap space is gone anyway so there’s no harm in missing the call to free (however, I do recognize the importance of having it anyway for closure, maintainability, and good practice). Am I right in this thinking?
      • 结果会如何?在我想来这个程序终止,然后堆空间被释放,所以即便不调用free函数不会造成损失(我知道使用使用free函数对于正常终止、可维护性以及一个好习惯的重要性)。我这样的想法正确吗?
    • Second, let’s say I have a program that acts a bit like a shell. Users can declare variables like aaa = 123 and those are stored in some dynamic data structure for later use. Clearly, it seems obvious that you’d use some solution that will calls some *alloc function (hashmap, linked list, something like that). For this kind of program, it doesn’t make sense to ever free after calling malloc because these variables must be present at all times during the program’s execution and there’s no good way (that I can see) to implement this with statically allocated space. Is it bad design to have a bunch of memory that’s allocated but only freed as part of the process ending? If so, what’s the alternative?
      • 第二,假设我有一个类似shell的程序。用户能够使用诸如aaa = 123的方式声明变量,并且为了后续方便使用,它们会以动态数据结构的方式存储。很明显的这会调用*alloc函数(例如哈希表,链表等数据结构)。对于这类程序,调用malloc后然后释放这些空间根本没用,因为这些变量将作用于整个程序执行期间,就我看来,还没有一个合适的方法去管理这些静态空间。在程序结束的时候才释放被分配的内存算是一个糟糕的设计吗?如果是的话,有其他实现方式吗?
        • shell: Windows的CMD就是一个shell。
  • Answers:
    • Paul Tomblin – vote: 403
      • Just about every modern operating system will recover all the allocated memory space after a program exits. The only exception I can think of might be something like Palm OS where the program’s static storage and runtime memory are pretty much the same thing, so not freeing might cause the program to take up more storage. (I’m only speculating here.)
        • 对于绝大多数现代操作系统来说,程序占用的内存会在结束后完全释放。唯一我能想到的例外是Palm OS,它的静态存储与运行时内存几乎一模一样,所以我猜不释放内存的话可能会让程序占据更多空间。
          • 译者注:最后这句话总感觉怪怪的。
      • So generally, there’s no harm in it, except the runtime cost of having more storage than you need. Certainly in the example you give, you want to keep the memory for a variable that might be used until it’s cleared.
        • 所以一般来说,不会有太大问题,除了运行时占用的空间比你实际需要的空间更多外,但这也只是因为你想为这个可能被使用的变量保持内存空间而造成的。
      • However, it’s considered good style to free memory as soon as you don’t need it any more, and to free anything you still have around on program exit. It’s more of an exercise in knowing what memory you’re using, and thinking about whether you still need it. If you don’t keep track, you might have memory leaks.
        • 不过,更好的方式是将不再需要的变量内存立即释放,并且在程序终止前释放所有内存。这更像一个练习,练习对内存的使用以及其判断释放时机的能力。如果你不保持追踪这些变化,就可能会造成内存泄漏。
      • On the other hand, the similar admonition to close your files on exit has a much more concrete result – if you don’t, the data you wrote to them might not get flushed, or if they’re a temp file, they might not get deleted when you’re done. Also, database handles should have their transactions committed and then closed when you’re done with them. Similarly, if you’re using an object oriented language like C++ or Objective C, not freeing an object when you’re done with it will mean the destructor will never get called, and any resources the class is responsible might not get cleaned up.
        • 在程序结束时因文件未关闭而造成的问题有多种,如缓冲区的数据没有被清除并输出,又或是临时文件没有被删除。对于数据库的句柄来说,则是完成事务提交后才能正常结束。同样的,如果你使用类似C++或Objective C这类面向对象语言,当结束时没有释放对象会使得垃圾回收机制不被正常调用,其持有的资源也不会被清理。
          • 译者注:
            • get flushed: 应该是指缓冲区的flush操作,大致是清空缓冲区并输出其内容。
            • transactions: 数据库的事务,事务是一种原子操作,原子操作表示这个操作无法中断(但出错会回滚到事务开始前),是最小操作单元。
    • compie – vote: 116
      • Yes you are right, your example doesn’t do any harm (at least not on most modern operating systems). All the memory allocated by your process will be recovered by the operating system once the process exits.
        • 你的观点没有问题,你假设的例子的确不会有造成任何损失(至少现代操作系统上是这样的)。所有被分配的内存都将在程序结束被操作系统恢复。
      • Source: Allocation and GC Myths (PostScript alert!)
        • Allocation Myth 4: Non-garbage-collected programs should always deallocate all memory they allocate.
          • 分配误区4:无垃圾回收机制的程序总是需要回收所有它分配的内存。
            • 译者注:Myth除了神话这个意思外,还有误区的意思,当我知道的时候咂吧了一下嘴。
        • The Truth: Omitted deallocations in frequently executed code cause growing leaks. They are rarely acceptable. but Programs that retain most allocated memory until program exit often perform better without any intervening deallocation. Malloc is much easier to implement if there is no free.
          • 事实:在频繁执行的代码中忽略释放内存的操作会引发内存泄漏,且这种泄漏造成的危害也难以接受。不过,直到程序退出才释放内存在性能上的表现通常更佳,因为不使用free函数的话,malloc的使用会更加便利。
            • 译者注:原文的意思表达/分隔符/首字母有够少见的。
        • In most cases, deallocating memory just before program exit is pointless. The OS will reclaim it anyway. Free will touch and page in the dead objects; the OS won’t.
          • 大多情况下,在程序结束前才回收内存毫无意义,因为操作系统会在结束后回收它们。并且,这种释放操作会涉及到无用对象的废弃页面,而操作系统不会。
            • 最后一句的free will touch and page in the dead objects,我不是很理解,我猜可能是说这些dead objects处于操作系统中某一page,而这个页面因为太久没调用,现在不在内存里面,如果要touch这个objects,就需要把这个废弃页面从硬盘或是其它地方调入内存,又因为马上就要结束程序了,这个操作很明显是多余且浪费性能的。
        • Consequence: Be careful with “leak detectors” that count allocations. Some “leaks” are good!
          • 结论:小心这些对分配计数的“内存泄漏探测者”,有的”泄漏”还是不错的!
      • That said, you should really try to avoid all memory leaks!
        • 也就是说,你的确应该避免所有内存泄漏!
      • Second question: your design is ok. If you need to store something until your application exits then its ok to do this with dynamic memory allocation. If you don’t know the required size upfront, you can’t use statically allocated memory.
        • 第二个问题:你的设计没错。如果你需要存储些东西直到这个应用结束,用动态内存分配来做是没问题的。如果你不直到待分配内存空间的大小,那自然不能用静态内存分配。
    • Trevor Boyd Smith – vote: 62
      • === What about future proofing and code reuse? ===
        • === 校对与复用 ===
      • If you don’t write the code to free the objects, then you are limiting the code to only being safe to use when you can depend on the memory being free’d by the process being closed … i.e. small one-time use projects or “throw-away”[1] projects)… where you know when the process will end.
        • 如果你不去释放对象,你的代码就必须在其因进程终止而释放内存前能安全运行。即那些小型的一次性项目或者“废弃”[1]项目,那些你知道程序会在什么时候终止的项目。
      • If you do write the code that free()s all your dynamically allocated memory, then you are future proofing the code and letting others use it in a larger project.
        • 如果你的确去释放了所有动态分配的内存,那么未来的校对会更加顺利,并且还能将其使用在一个大项目中。
      • [1] regarding “throw-away” projects. Code used in “Throw-away” projects has a way of not being thrown away. Next thing you know ten years have passed and your “throw-away” code is still being used).
        • [1] 关于“废弃”项目。使用在“废弃”项目的代码有时并没有真正被废弃,十年后你可能发现它还在工作。
      • I heard a story about some guy who wrote some code just for fun to make his hardware work better. He said “just a hobby, won’t be big and professional“. Years later lots of people are using his “hobby” code.
        • 我听说个一个故事,有些人为了娱乐而写了些让它硬件更高效的代码。他说“仅仅只是兴趣,不怎么专业”。几年后仍然有很多人在用它因兴趣开发的代码。

You may also like...

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注