为什么Java和Python的垃圾回收方法不同?
为什么Java和Python的垃圾回收方法不同?
Python使用引用计数方式来处理对象生命周期。因此,没有使用的对象会立即被销毁。
而在Java中,垃圾回收器(GC)会在特定时间销毁不再使用的对象。
为什么Java选择这种策略,以及这种策略的好处是什么?
这比Python的方法更好吗?
实际上,引用计数和Sun JVM使用的策略都是不同类型的垃圾收集算法。
追踪和引用计数是寻找死对象的两种广泛方法。在追踪中,GC从“根”开始 - 例如堆栈引用,并跟踪所有可达(活动的)对象。无法到达的所有内容都被视为死亡对象。在引用计数中,每次修改引用计数时,对象的计数都会更新。任何引用计数为零的对象都被视为死亡对象。
基本上,所有GC实现都有权衡,但是追踪通常适用于高吞吐量(即快速)操作,但是暂停时间较长(UI或程序可能会冻结的更长时间段)。引用计数可以分块操作,但总体上会更慢。这可能意味着较少的冻结,但总体性能较差。
此外,引用计数GC需要一个循环检测器来清除任何不被其引用计数捕获的循环中的对象。 Perl 5在其GC实现中没有循环检测器,并且可能会泄漏循环内存。
还进行了研究,以获得两全其美的效果(低暂停时间,高吞吐量):http://cs.anu.edu.au/~Steve.Blackburn/pubs/papers/urc-oopsla-2003.pdf
使用引用计数存在一些缺陷。其中最常被提及的是循环引用:假设A引用B,B引用C,C引用B。如果A放弃对B的引用,B和C仍然具有1个引用计数,并且不会因传统的引用计数而被删除。CPython(引用计数不是Python本身的一部分,而是其C实现的一部分)使用单独的垃圾回收例程定期检测循环引用...
另一个缺点:引用计数可能会使执行变慢。每次引用和取消引用对象时,解释器/虚拟机必须检查计数是否下降到0(然后在计数为0时进行回收)。垃圾回收不需要这样做。
此外,垃圾回收可以在单独的线程中执行(虽然可能有些棘手)。对于拥有大量RAM并且仅缓慢使用内存的进程,您可能根本不想进行GC!在性能方面,引用计数在那里会有一些缺陷...