【问题标题】:Not deleting dynamically allocated memory and let it get free by the OS after programme termination在程序终止后不删除动态分配的内存并让它由操作系统释放
【发布时间】:2015-10-12 14:41:37
【问题描述】:

我已阅读此问题和答案 dynamically allocated memory after program termination, 我想知道是否可以不删除动态分配的内存并让它在程序终止后由操作系统释放。 那么,如果我为程序中需要的对象分配了一些内存,是否可以在程序结束时跳过删除它们,以使代码运行得更快?

【问题讨论】:

  • 这不是一个好的做法,当大块内存没有被删除时可能会导致意外行为。如果您不想管理自己,请使用 boost::unique_ptr。它会被自己删除。
  • 听起来你会更喜欢垃圾收集语言,但你可能在真正不需要的时候使用动态内存分配。
  • @crashmstr : 确实。
  • 释放动态分配真的需要更多时间吗?
  • 我只是好奇,感谢您的回答!所以不释放动态分配的内存是不好的做法。我将阅读有关 shared_ptr 和 unique_ptr 的信息。

标签: c++ memory-management memory-leaks heap-memory


【解决方案1】:

简短的回答是肯定的,你可以,长的答案是可能你最好不要那样做:如果你的代码需要重构并变成一个库,您将大量的技术债务交给了将要从事这项工作的人,可能就是您。

此外,如果您有一个真实的、难以发现的内存泄漏(不是由您故意不释放长寿命对象引起的内存泄漏),那么使用 valgrind 进行调试将非常耗时,因为相当多噪音和误报的数量。

看看std::shared_ptrstd::unique_ptr。后者没有开销。

【讨论】:

    【解决方案2】:

    大多数正常的操作系统会在终止时释放进程拥有的所有内存和本地资源(操作系统可能会以惰性方式执行此操作,或减少其共享计数器,但这在问题上并不重要)。因此,跳过释放这些资源是安全的。

    但是,这是非常坏的习惯,你几乎一无所获。如果您发现释放对象需要很长时间(例如在很长的对象列表中走动),您应该优化您的代码并选择更好的算法。

    另外,虽然操作系统会释放所有本地资源,但也有例外,如共享内存和全局空间信号量,需要您明确释放。

    【讨论】:

      【解决方案3】:

      首先,C++ 中的第一条规则是:

      除非你真的需要,否则避免动态分配!

      不要轻易使用new;即使它被安全地包裹在std::make_uniquestd::make_shared 中也不行。在 C++ 中创建类型实例的标准方法是:

      T t;

      在 C++ 中,只有当对象的寿命超过其最初创建的范围时,才需要动态分配。

      如果且仅当您需要动态分配对象时,才考虑使用std::shared_ptrstd::unique_ptr。当不再需要对象时,它们会自动释放。

      第二,

      是否可以在程序结束时跳过删除它们,以便 让代码运行得更快?

      绝对不是,因为有“为了让代码运行得更快”部分。这将是过早的优化。


      这些是基本点。

      但是,您仍然需要考虑什么是“真正的”或严重的内存泄漏。

      这是一个严重的内存泄漏:

      #include <iostream>
      
      int main()
      {
          int count;
          std::cin >> count;
          for (int i = 0; i < count; ++i)
          {
              int* memory = new int[100];
          }
      }
      

      这还不错,因为记忆“永远丢失了”;一旦进程结束,任何远程现代操作系统都会为您清理所有内容(请参阅 Kerrek SB 在您的链接问题中的回答)。

      这很糟糕,因为内存消耗并非恒定不变;它会随着用户输入而不必要地增长。

      这是另一个糟糕的内存泄漏:

      void OnButtonClicked()
      {
          std::string* s = new std::string("my"); // evil!
          label->SetText(*s + " label");
      }
      

      这段(虚构的和稍微做作的)代码会随着每次按钮点击而增加内存消耗。程序运行的时间越长,占用的内存就越多。

      现在比较一下:

      int main()
      {
          int* memory = new memory[100];
      }
      

      在这种情况下,内存消耗是恒定的;它不依赖于用户输入,并且不会随着程序运行的时间变大。虽然对于这么小的测试程序来说是愚蠢的,但在 C++ 中有 种情况,故意不解除分配是有意义的。

      想到了单身人士。在 C++ 中实现 Singleton 的一个非常好的方法是动态创建实例并且永远不会删除它;这避免了所有破坏顺序问题(例如,当Log 已经被破坏时,SettingsManager 在其析构函数中写入Log)。当操作系统清除内存时,不再执行任何代码,您是安全的。

      您可能永远不会遇到避免解除分配是个好主意的情况。但要警惕软件工程中的“总是”和“从不”规则,尤其是在 C++ 中。良好的内存管理比将每个 newdelete 匹配要困难得多。

      【讨论】:

      • 什么!!!避免使用动态内存?你到底在推荐什么?您必须这样做的唯一原因是不知道如何使用它。 Java完全基于动态内存。你在说什么?对不起,只能投反对票。
      • @LuisColorado:Java 是一种不同的语言。您在这里反对一个完善的、普遍接受的 C++ 指南。您的声明是否有权威来源?
      • “除非你真的需要它”确实很常见。更不用说生命周期和所有权,堆栈空间是有限的,如果您有大量数据,您最终需要解决动态分配问题,或者让其他人在某种集合中为您完成。
      • @Calvin:嗯,很明显,当我反对不必要的动态分配时,我并不打算避免使用 std::vector 等。我反对初学者在 C++ 中更新所有内容的错误只是因为 Java 具有垃圾收集功能:) 智能指针在一定程度上缓解了这个问题,但并没有解决它。
      • @Calvin:您需要多久进行一次动态分配主要取决于您的应用程序域。无论如何,这应该是一个有意识的选择,而不是默认。
      猜你喜欢
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      • 2011-10-07
      • 2018-01-14
      • 2011-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多