当前位置:  开发笔记 > 编程语言 > 正文

为什么Java和Python垃圾收集方法不同?

如何解决《为什么Java和Python垃圾收集方法不同?》经验,为你挑选了5个好方法。

Python使用引用计数方法来处理对象的生命周期.因此,不再使用的对象将立即被销毁.

但是,在Java中,GC(垃圾收集器)会销毁在特定时间不再使用的对象.

为什么Java选择这种策略,这有什么好处?

这比Python方法更好吗?



1> Daren Thomas..:

使用引用计数存在缺点.其中最常提到的是循环引用:假设A引用B,B引用C和C引用B.如果A将其引用丢弃到B,则B和C仍将具有引用计数1并且不会被删除与传统的引用计数.CPython(引用计数不是python本身的一部分,但是它的C实现的一部分)捕获带有单独的垃圾收集例程的循环引用,它定期运行...

另一个缺点:引用计数会使执行速度变慢.每次引用和解除引用对象时,解释器/ VM必须检查计数是否已降至0(如果确实,则取消分配).垃圾收集不需要这样做.

此外,垃圾收集可以在一个单独的线程中完成(虽然它可能有点棘手).在具有大量RAM的机器上以及仅缓慢使用内存的进程中,您可能根本不想进行GC操作!就性能而言,引用计数在某种程度上是一个缺点......


值得注意的另一个区别是,通过引用计数的急切GC始终使用"最小"内存(循环依赖性情况除外),而Java的惰性方法可能会导致JVM暂时使用比实际需要更多的内存,直到GC运行带来它重新排成一行.Java的方法以内存为代价提供速度,并且在内存充足时具有优势.当它很稀缺时,Python的方法会更好.

2> Luke Quinane..:

实际上,引用计数和Sun JVM使用的策略都是不同类型的垃圾收集算法.

跟踪死对象有两种广泛的方法:跟踪和引用计数.在跟踪GC时,从"根"开始 - 诸如堆栈引用之类的东西,并跟踪所有可到达(实时)对象.任何无法达到的东西都被视为死亡.在引用计数中,每次修改引用时,所涉及的对象都会更新其计数.引用计数设置为零的任何对象都被视为已死.

基本上所有GC实现都存在权衡,但跟踪通常适用于高吞吐量(即快速)操作但具有更长的暂停时间(UI或程序可能冻结的较大间隙).引用计数可以在较小的块中运行,但总体上会较慢.这可能意味着更少的冻结,但总体上表现较差.

另外,引用计数GC需要一个循环检测器来清理循环中的任何对象,这些对象不会被它们的引用计数单独捕获.Perl 5在其GC实现中没有循环检测器,并且可能泄漏循环的内存.

还进行了研究以获得两全其美(低暂停时间,高吞吐量):http: //cs.anu.edu.au/~Steve.Blackburn/pubs/papers/urc-oopsla-2003.pdf



3> Eli Courtwri..:

达伦托马斯给出了一个很好的答案.但是,Java和Python方法之间的一个重要区别是,在常见情况下(没有循环引用)引用计数对象会立即清除,而不是在某些不确定的日期.

例如,我可以在CPython中编写草率的,不可移植的代码,例如

def parse_some_attrs(fname):
    return open(fname).read().split("~~~")[2:4]

并且我打开的文件的文件描述符将立即被清除,因为只要对打开文件的引用消失,文件就会被垃圾收集并释放文件描述符.当然,如果我运行Jython或IronPython或者可能是PyPy,那么垃圾收集器不一定会运行到很久以后; 可能我会先用完文件描述符而我的程序会崩溃.

所以你应该编写看起来像的代码

def parse_some_attrs(fname):
    with open(fname) as f:
        return f.read().split("~~~")[2:4]

但有时人们喜欢依赖引用计数来永远释放资源,因为它有时会使你的代码变短.

我会说最好的垃圾收集器是性能最好的垃圾收集器,它目前似乎是Java风格的分代垃圾收集器,可以在一个单独的线程中运行并具有所有这些疯狂的优化,等等.编写代码应该可以忽略不计,理想情况下不存在.


好答案.对我来说,你的答案中的一个主要观点是在第二个例子中没有使用显式的`close()`.在python中编写的代码要少得多.这在http://docs.python.org/howto/doanddont.html上解释(搜索"with open")

4> Espo..:

我认为IBM 的文章" Java理论与实践:垃圾收集的简史 "应该有助于解释您的一些问题.



5> mfx..:

如果你有足够的内存,垃圾收集比引用计数更快(更有效).例如,复制gc遍历"实时"对象并将它们复制到新空间,并且可以通过标记整个存储区域在一个步骤中回收所有"死"对象.如果你有足够的内存,这是非常有效的.世代收藏品使用"大多数物品年轻化"的知识; 通常只有百分之几的对象必须被复制.

[这也是为什么gc可以比malloc/free更快的原因]

引用计数比垃圾收集更节省空间,因为它在内存无法访问时回收内存.当你想要将终结器附加到对象时(例如,一旦File对象无法访问就关闭文件),这很好.即使只有百分之几的内存空闲,引用计数系统也可以工作.但是,必须在每个指针赋值时递增和递减计数器的管理成本花费了大量时间,并且仍然需要某种垃圾收集来回收循环.

因此,权衡是明确的:如果您必须在内存受限的环境中工作,或者您需要精确的终结器,请使用引用计数.如果您有足够的内存并且需要速度,请使用垃圾回收.

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有