Java 使用空值释放堆内存,然后使用GC

Java 使用空值释放堆内存,然后使用GC,java,memory,memory-management,garbage-collection,Java,Memory,Memory Management,Garbage Collection,假设我有以下代码: DataStructure hugeData = Data.readLotsOfStuff(); // like gigabytes DataStructure processedData = processData(hugeData); // now I don't need hugeData, so hugeData = null; System.gc(); 这样明确地释放内存是一种好的做法吗?关心这些事情通常不是一种好的做法。它使代码更难阅读(每多读一行都需要时间),

假设我有以下代码:

DataStructure hugeData = Data.readLotsOfStuff(); // like gigabytes
DataStructure processedData = processData(hugeData);
// now I don't need hugeData, so
hugeData = null;
System.gc();

这样明确地释放内存是一种好的做法吗?

关心这些事情通常不是一种好的做法。它使代码更难阅读(每多读一行都需要时间),如果是
System.gc()
,则可能会发生所有错误的运行时行为。它会混淆内部垃圾收集器的预测,通常会触发非常重/慢速的GCs。(特别是如果您的代码用于具有并发使用的更大应用程序中,那就糟了)

提前为局部变量(硬引用)置零会出现以下问题:

a) 如果您的引用只使用到某一点,并且您的代码块要大得多,那么它可能太大了

b) 将局部变量设置为final是很好的,如果您知道变量没有变化,那么可以更好地阅读代码。无论如何,这些最终变量不能为空

c) Java(运行时)编译器和解释器变得越来越智能。让VM决定何时释放引用

说了这么多。如果将变量的作用域/块留在方法中,则不能期望引用的对象变得不可访问。将变量的作用域缩小看起来不错,但对于提前释放引用的问题,它并没有起到多大作用(除非稍后的作用域重新使用插槽)。如果该方法是长时间运行的(可能是一个无止境的循环),那么最好将引用设为null。但只有当你引用了一个非常大的对象树,它才能使对象保持活力。否则,额外的赋值和代码就不值得了

method() {
  if (...) {
    byte[] ref=new byte[1*MB];
  }
  // B
  while(true) { ... }
}
在本例中,大1MB缓冲区不在位置“B”的作用域中,但它仍然在运行时java堆栈上(java VM没有作用域的概念,ref保留在局部变量表槽中,直到方法离开)。由于该方法不会(很快)终止,因此可以将其设为null。拆分方法是更好的主意


永远不要调用System.gc()。

这被认为是一种不好的做法。若不可访问的对象保留的内存是必需的,那个么垃圾收集器的运行无论如何都会完成。此外,如果无法保证(尽最大努力释放无法访问的内存),那么在不再需要引用时将指针设置为null是一种好的做法(尽管局部变量引用很少需要,只有类静态和实例成员)。显式调用垃圾回收器不是一个好方法。