Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java和Python垃圾收集方法不同?_Java_Python_Garbage Collection - Fatal编程技术网

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

为什么Java和Python垃圾收集方法不同?,java,python,garbage-collection,Java,Python,Garbage Collection,Python使用引用计数方法来处理对象生命周期。因此,一个不再有用的对象将立即被销毁 但是,在Java中,GC(垃圾收集器)销毁在特定时间不再使用的对象 Java为什么选择这种策略?这种策略的好处是什么 这比Python方法好吗?我认为IBM的文章“”应该有助于解释您的一些问题。使用引用计数有缺点。其中提到最多的是循环引用:假设A引用B、B引用C和C引用B。如果A放弃对B的引用,B和C的引用计数仍然为1,并且不会使用传统的引用计数删除。CPython(引用计数不是python本身的一部分,而是其

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

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

Java为什么选择这种策略?这种策略的好处是什么


这比Python方法好吗?

我认为IBM的文章“”应该有助于解释您的一些问题。

使用引用计数有缺点。其中提到最多的是循环引用:假设A引用B、B引用C和C引用B。如果A放弃对B的引用,B和C的引用计数仍然为1,并且不会使用传统的引用计数删除。CPython(引用计数不是python本身的一部分,而是其C实现的一部分)通过一个单独的垃圾收集例程捕获循环引用,该例程定期运行

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


此外,垃圾收集可以在单独的线程中完成(尽管这可能有点棘手)。在具有大量RAM的机器上,对于使用内存速度较慢的进程,您可能根本不想执行GC!引用计数在性能方面会有点缺陷…

Darren Thomas给出了一个很好的答案。然而,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风格的分代垃圾收集器,可以在单独的线程中运行,并且具有所有这些疯狂的优化,等等。编写代码的方式的差异应该可以忽略不计,理想情况下是不存在的。

最新的Sun Java VM实际上有多种GC算法,您可以对其进行调整。JavaVM规范有意省略了指定实际GC行为,以允许不同VM使用不同(和多个)GC算法

例如,对于所有不喜欢默认sunjavavmgc行为的“停止世界”方法的人来说,有一些VM允许实时应用程序在Java上运行


由于Java VM规范是公开的,因此(理论上)没有任何东西可以阻止任何人实现使用CPython的GC算法的Java VM。

在多线程环境中,引用计数尤其难以有效地完成。我不知道如果不进入硬件辅助事务或类似(当前)不寻常的原子指令,您将如何开始这样做


引用计数易于实现。JVM在竞争实现中投入了大量资金,因此,它们为非常困难的问题实现了非常好的解决方案也就不足为奇了。然而,在JVM上定位您喜爱的语言变得越来越容易。

如果您有足够的内存,垃圾收集比引用计数更快(更省时)。例如,复制gc遍历“活动”对象并将其复制到一个新空间,通过标记整个内存区域,可以在一个步骤中回收所有“死”对象。这是非常有效的,如果你有足够的内存。代代相传的收藏品使用了“大多数物品在年轻时死亡”的知识;通常只需复制百分之几的对象

[这也是gc比malloc/free更快的原因]

引用计数比垃圾收集更节省空间,因为它在无法访问内存时立即回收内存。当您希望将终结器附加到对象时(例如,一旦文件对象无法访问,就关闭文件),这非常好。即使只有百分之几的内存可用,引用计数系统也可以工作。但是在每次指针分配时必须增加和减少计数器的管理成本花费了大量时间,并且仍然需要某种垃圾收集来回收周期


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

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

有两种广泛的方法来追踪死亡对象:追踪和引用计数。在跟踪过程中,GC从“根”开始,例如堆栈引用,并跟踪所有可访问(活动)对象。任何联系不到的东西都被认为是死的。在引用计数中,每次修改引用时,所涉及的对象的计数都会更新。任何引用计数设置为零的对象都被视为死对象

对于基本上所有的GC实现,都有一些折衷,但跟踪通常有利于h