JVM字节码是否能够显式释放内存?

7

几种计算机编程语言使用JVM字节码作为其解释器/编译器的目标语言。对我来说,许多新的编程语言(不到15年)都在JVM上运行,我想知道是否所有这些编程语言都禁止了显式内存释放:

是否可以通过任何指令显式分配-释放字节码中的内存?相反,垃圾回收器总是负责内存释放吗?

3个回答

7

JVM抽象了所有的内存管理。没有用于内存释放的字节码,就像没有用于内存分配或直接内存访问的字节码一样。如果您想要这样做,必须使用本地代码,直接或间接地。


2
是的。你可以通过查看完整的字节码指令集来确认这一点 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html - slim
有一些指令,如“new”或“newarray”,它们隐式地分配内存。从您的回答和字节码指令集清单中我了解到,“del”这样的东西并不存在。是否可能在本机代码中实现类似“del”的指令,然后从字节码中调用它?这样,您可以将假设的编程语言内存释放指令编译为字节码+您的小型本机代码。 - Pablo Francisco Pérez Hidalgo
1
没有任何有用的方式。'new'等的实现取决于具体实现,因此即使您可以编写一个可以入侵堆的'del',它也不会稳定或可移植。有C到字节码编译器。它们使用Java数组模拟malloc、free、指针算术等。 - slim
1
@pablo JVM甚至不能保证为new或newarray分配内存,更不用说创建实际的堆对象了。它只是一个抽象概念。 - Antimony

2
JVM的绝对原则之一是对象的存在至少与对它们的引用同等长。如果一个对象组内的对象彼此持有强引用,但是组外仅有的引用被封装在WeakReference对象中,那么该组内的所有对象和引用都将同时消失(WeakReference对象可能仍然存在,但不再持有任何引用)。
这意味着除非JVM确信不存在对该对象的引用,否则不能重复使用对象的内存。由于确保不存在对某个特定对象的引用需要的时间与对所有年龄相同或更新的对象进行垃圾回收所需的时间几乎相同,因此试图更早地回收内存实际上没有好处。特别是考虑到GC在需要内存时运行。在需要内存之前,释放内存并没有任何优势。

1

两年后,当我发现Apache Spark中的Tungsten项目使用JVM来分配和释放堆内存时,我回到了这个问题。

这不是新鲜事,所以它是可行的。你可以在这里找到更多细节,我得到了以下示例:

public DirectIntArray(long size) {
  startIndex = unsafe.allocateMemory(size * INT_SIZE_IN_BYTES);
  unsafe.setMemory(startIndex, size * INT_SIZE_IN_BYTES, (byte) 0);
  }
}

public void setValue(long index, int value) {
  unsafe.putInt(index(index), value);
}

public int getValue(long index) {
  return unsafe.getInt(index(index));
}

private long index(long offset) {
  return startIndex + offset * INT_SIZE_IN_BYTES;
}

public void destroy() {
  unsafe.freeMemory(startIndex);
}

GC 完全不知道这种方式分配的内存。我称之为“hack”,因为它使用代码反射来打开应该只由 ClassLoader 用于实例创建的内部方法来分配内存。

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