JVM无垃圾回收

20

我在许多帖子中读到,无法在Sun的JVM上关闭垃圾收集。然而,为了我们的研究项目,我们需要这个功能。有人可以推荐一个没有垃圾收集或允许关闭它的JVM实现吗?谢谢。


4
没有垃圾回收的Java就像C/C++一样! - Mitch Wheat
1
根据 http://forums.java.net/jive/thread.jspa?messageID=208939&tstart=0 的说法,在早期版本的Java中可以禁用gc,但现在已不再可能。 - James P.
8
@Mitch Wheat,不是的。它与C++相差甚远,没有缓冲区溢出,并且几乎没有未定义行为。 - L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
3
没有垃圾回收,就没有内存回收,因此你会出现大量泄漏。 - JUST MY correct OPINION
Java没有垃圾回收几乎是不可能的。Java中的每个小函数都会分配一些东西,无论是main方法的数组还是字符串。这时候为什么不选择一个更合适的语言呢? - RecursiveExceptionException
显示剩余4条评论
10个回答

26
我希望找到一种快速的方法来保留用于简单概念验证的所有对象在内存中。简单的方法是使用堆大小足够大,使得GC不需要运行的JVM运行。将-Xmx-Xms选项设置为较大的值,并打开GC日志以确认在测试期间GC不会运行。这比修改JVM更快且更直接。

事后看来,这可能行不通。我依稀记得看到的证据表明JVM并不总是尊重-Xms设置,特别是如果它非常大。尝试这种方法仍然值得一试,然后再尝试一些更困难的方法...比如修改JVM。

此外,整个过程让我觉得对于您实际想要实现的目标来说是不必要的(甚至是适得其反的)。除非它们是垃圾,否则GC不会丢弃对象。如果它们是垃圾,您将无法使用它们。禁用/抵消GC的系统的性能不会反映出真实应用程序的性能。


更新 - 从Java 11开始,您可以选择使用更简单的选项,即使用Epsilon(无操作)垃圾收集器;请参见

在启动JVM时,您需要添加以下选项:

-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC

当堆被填满时,不会尝试收集垃圾。相反,Epsilon GC 终止 JVM。

8
根据您的需求,以下方案或许可行:
使用 -Xbootclasspath 选项,您可以指定自己实现的 API 类。例如,您可以覆盖 Object 的实现,并在构造函数中添加 globalList.add(this) 以防止对象被垃圾回收。这虽然是一种 hack 方法,但对于简单的案例研究可能已足够。
另一个选择是使用开源 jvm 并注释掉启动垃圾回收的部分。我想这并不复杂。

1
覆盖Object听起来像个好主意。但是当我尝试时,它给了我一个带有巨大堆栈跟踪的错误。我认为这是有道理的,因为我想在Object的构造函数中执行的任何代码都需要调用Object的构造函数。 - H-H
2
好的观点。一个简单的globalList.add(this)可能会导致无限递归。你需要做一些更聪明的事情。例如,您可以实现自己的列表结构,该结构被排除在列表中插入的范围之外。 - aioobe
这会防止分代收集中的“小型集合”循环吗? - cody

4
Sun的JVM没有这个选项。据我所知,其他JVM也没有这个选项。
您并未说明您确切地想要实现什么,但您有两个选择:一是使用分析器并查看GC的确切操作,这样您就可以考虑到它的影响。另一个选择是从源代码编译其中一个JVM,并从那里禁用GC。

1
谢谢你的回答。我基本上是在对Java程序进行分析。我想找到一种快速的方法来将所有对象保留在内存中,以进行简单的初步概念验证。 - H-H

2

如果没有必要(否则您的应用程序将耗尽内存),并且如果您不需要GC,则可以关闭GC。如果不需要GC,它就不应该运行。

最简单的选择是不丢弃任何对象,这将避免执行GC(并将最大内存设置得非常高,以便您不会耗尽内存)。

您可能会发现,在启动时会发生GC,并且您可以考虑在运行时接受无GC。


2

1

你能获取一个开源的JVM并禁用它的GC,例如Sun's Hotspot吗?

如果没有垃圾回收,你会期望像这样的代码语义是什么?

public myClass {

      public void aMethod() {

            String text = new String("xyz");

      }

}

在没有垃圾回收的情况下,任何使用new关键字创建的对象并且只有栈作用域引用的对象都无法被回收。即使你自己的类可以决定不使用这样的局部变量,或者只使用基本类型,我也不知道你如何安全地使用任何标准的Java库。
我很想听听您的使用场景。

1
也许你可以尝试将虚拟机的可用内存设置得足够大,以便永远不需要运行垃圾回收。
根据我的(尽管有限)经验,我建议默认情况下虚拟机非常懒惰且非常不愿意运行垃圾回收。
通过使用"-Xmx 16384M"(或类似的设置),并确保你的研究对象始终保持在这个限制以下,可能会给你希望获得的环境,尽管即便如此,这也无法完全保证。

1

看看Oracle的JRockit JVM。我在Intel硬件上使用这个JVM时看到了非常好的近确定性性能,您可以使用Mission Control实用程序来探测运行时的性能。

虽然您无法完全关闭GC,但我相信您可以使用-Xnoclassgc选项禁用类的收集。 GC可以调整为最小化延迟,但会导致内存消耗增加。如果您选择这条路,您可能需要许可证将延迟降至所需的水平。

还有一个实时版本的JRockit JVM可用,但我认为没有免费提供给开发者使用的版本。


1

实际上有一种肮脏的方法可以暂时暂停GC。首先在Java中创建一个虚拟数组。然后,在JNI中使用GetPrimitiveArrayCritical函数获取指向该数组的指针。Sun JVM将禁用GC以确保该数组永远不会移动,并且指针保持有效。要重新启用GC,可以在指针上调用ReleasePrimitiveArrayCritical函数。但是这非常特定于实现,因为其他VM实现可能会固定对象而不是完全禁用GC。(已在Oracle Jdk 7和8上测试可行)


0

如果我遇到这个问题,我会选择IBM的Jikes Research Virtual Machine,因为:

  • 运行时系统本身是用Java编写的(带有特殊扩展)
  • 整个系统都被设计成一个研究工具,相对容易调整。

你不能永远关闭GC,因为Java程序确实会分配内存,最终你会耗尽内存,但是你可以通过告诉JVM在堆变得非常大之前不要开始收集来延迟GC的时间,这在你的实验期间可能是可行的。(这个技巧在其他JVM上也可能有效,但我不知道在哪里找到旋钮来启动它。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接