Memory management 您什么时候可能不想使用垃圾收集?

Memory management 您什么时候可能不想使用垃圾收集?,memory-management,garbage-collection,Memory Management,Garbage Collection,垃圾收集从LISP的早期就开始了,现在——几十年过去了——大多数现代编程语言都使用它 假设您正在使用这些语言中的一种,您有什么理由不使用垃圾收集,而是以某种方式手动管理内存分配 你曾经这样做过吗 如果可能,请给出可靠的例子。内存分配?不,我认为总司令比我更擅长 但稀缺的资源分配,如文件句柄、数据库连接等。?我编写代码在完成后关闭它们。GC不会帮你的 我能想到几个: 确定性释放/清除 实时系统 不放弃一半的内存或处理器时间-取决于算法 更快的内存alloc/dealloc和特定于应用程序的内存分配

垃圾收集从LISP的早期就开始了,现在——几十年过去了——大多数现代编程语言都使用它

假设您正在使用这些语言中的一种,您有什么理由不使用垃圾收集,而是以某种方式手动管理内存分配

你曾经这样做过吗


如果可能,请给出可靠的例子。

内存分配?不,我认为总司令比我更擅长

但稀缺的资源分配,如文件句柄、数据库连接等。?我编写代码在完成后关闭它们。GC不会帮你的

我能想到几个:

确定性释放/清除

实时系统

不放弃一半的内存或处理器时间-取决于算法

更快的内存alloc/dealloc和特定于应用程序的内存分配、释放和管理。基本上是编写自己的内存—通常用于性能敏感的应用程序。这可以在相当清楚地理解应用程序的行为的情况下完成。对于通用GC(如Java和C#),这是不可能的

编辑


这就是说,GC对社区的大部分人来说无疑是好的。它允许我们更多地关注问题域,而不是漂亮的编程技巧或模式。不过,我仍然是一个“非托管”C++开发人员。在这种情况下,良好的实践和工具会有所帮助。

使用垃圾收集器可能很难编写实时应用程序。可能使用在另一个线程中工作的增量GC,但这是额外的开销。

我能想到的一种情况是,当您处理的数据集达到数百兆字节或更多时。根据具体情况,您可能希望在使用完此内存后立即释放它,以便其他应用程序可以使用它


此外,在处理某些非托管代码时,可能会出现这样的情况:您可能希望阻止GC收集某些数据,因为非托管部分仍在使用这些数据。尽管我仍然需要想出一个很好的理由,为什么仅仅保留对它的引用可能不够好P

我处理过的一种情况是图像处理。在研究裁剪图像的算法时,我发现托管库的速度不够快,无法在大型图像上或一次在多个图像上进行裁剪


在我的情况下,以合理的速度处理图像的唯一方法是使用非托管代码。这是在C#NET的一个小型个人项目中工作时,我不想学习第三方库,因为项目的规模太大,而且我想学习它来提高自己。可能有一个现有的第三方库(可能是Paint.NET)可以做到这一点,但它仍然需要非托管代码。

我不太理解这个问题。既然您询问的是一种使用GC的语言,我想您询问的示例如下

  • 即使我知道某个引用已经死了,也要故意保留它,也许是为了重用该对象以满足将来的分配请求
  • 跟踪某些对象并显式关闭它们,因为它们包含的资源无法通过垃圾收集器轻松管理(打开文件描述符、屏幕上的窗口等等)
  • 我从来没有找到做1的理由,但2是偶尔出现的理由。许多垃圾收集器提供了终结机制,这是一个绑定到对象的操作,系统在回收对象之前运行该操作。但是,系统通常无法保证终结器是否实际运行,因此终结的效用有限

    在垃圾收集语言中,我做的主要事情是密切关注每单位其他工作的分配数量。分配通常是性能瓶颈,尤其是在Java或.NET系统中。对于像ML、Haskell或LISP这样的语言来说,这不是一个问题,它们的设计理念通常是程序将疯狂地分配


    编辑:回复评论的时间更长

    并非所有人都理解,在性能方面,分配器和GC必须被视为一个团队。在最先进的系统中,分配是从连续的空闲空间(“托儿所”)完成的,速度与测试和增量一样快。但是,除非分配的对象非常短命,否则该对象会招致一笔债务:它必须从托儿所复制出来,如果它存在一段时间,可能会通过几代复制。最好的系统使用连续的可用空间进行分配,并在某些情况下将旧对象从复制切换到标记/扫描或标记/扫描/压缩。因此,如果你非常挑剔,你可以忽略分配,如果

    • 您知道您正在处理一个从连续的空闲空间(托儿所)分配的最先进的系统
    • 您分配的对象非常短暂(在托儿所中少于一个分配周期)
    否则,最初分配的对象可能很便宜,但它们代表了以后必须完成的工作。即使分配本身的成本是一个测试和增量,减少分配仍然是提高性能的最佳方法。我已经使用最先进的分配器和收集器调优了几十个ML程序,这仍然是事实即使使用最好的技术,内存管理也是常见的性能瓶颈

    您会惊讶地发现,有多少分配器甚至不能很好地处理非常短暂的对象。Lua5.1.4(可能是脚本语言中速度最快的一种,有一代GC)替换了30个替换序列,每个替换都分配了一个大表达式的新副本,这大大加快了我的速度