如何在Java中释放内存?

如何在Java中释放内存?,java,garbage-collection,Java,Garbage Collection,Java中有没有类似于C的free()函数的释放内存的方法?还是将对象设置为null并依赖GC是唯一的选项 System.gc(); 运行垃圾收集器 调用gc方法表明Java虚拟机花费精力回收未使用的对象,以使它们当前占用的内存可用于快速重用。当控件从方法调用返回时,Java虚拟机已尽最大努力从所有丢弃的对象中回收空间 不推荐。 编辑:我在2009年写了最初的回复。现在是2015年 在Java出现的20年中,垃圾收集器的性能稳步提高。在这一点上,如果您手动调用垃圾回收器,您可能需要考虑其他方

Java中有没有类似于C的
free()
函数的释放内存的方法?还是将对象设置为null并依赖GC是唯一的选项

System.gc(); 
运行垃圾收集器

调用gc方法表明Java虚拟机花费精力回收未使用的对象,以使它们当前占用的内存可用于快速重用。当控件从方法调用返回时,Java虚拟机已尽最大努力从所有丢弃的对象中回收空间

不推荐。

编辑:我在2009年写了最初的回复。现在是2015年

在Java出现的20年中,垃圾收集器的性能稳步提高。在这一点上,如果您手动调用垃圾回收器,您可能需要考虑其他方法:

  • 如果您在有限数量的机器上强制GC,那么让负载平衡器点远离当前机器,等待它完成为连接的客户端提供服务,在一段时间后超时以挂起连接,然后硬重启JVM可能是值得的。这是一个糟糕的解决方案,但如果您查看System.gc(),强制重启可能是一个权宜之计
  • 考虑使用不同的垃圾收集器。例如,(过去六年中新增的)G1采集器是一种低暂停模式;总体而言,它使用了更多的CPU,但最好不要强制执行时硬停止。由于服务器CPU现在几乎都有多个核心,因此这是一个非常好的折衷方案
  • 查看您的内存使用情况。特别是在java的更新版本中,如果没有那么多的长期运行对象,那么就要考虑堆中NeGEN的大小。newgen(young)是分配新对象的地方。对于Web服务器来说,为请求创建的所有内容都放在这里,如果这个空间太小,Java将花费额外的时间将对象升级到寿命更长的内存中,在那里杀死它们的成本更高。(如果newgen稍微太小,您将为此付费。)例如,在G1中:
    • XX:G1NewSizePercent(默认值为5;可能不重要。)
    • XX:G1MaxNewSizePercent(默认值为60;可能会提高此值。)
  • 考虑一下告诉垃圾回收员你不适合长时间的停顿。这将导致更频繁的GC运行,以允许系统保持其余的约束。在G1中:
    • XX:MaxGCPauseMillis(默认为200。)

Java使用托管内存,因此分配内存的唯一方法是使用
new
操作符,而释放内存的唯一方法是依赖垃圾收集器

这(PDF)可能有助于解释发生了什么

您还可以调用
System.gc()
,建议垃圾收集器立即运行。但是,最终决定权在Java运行时,而不是您的代码

据报道,

调用gc方法表明 Java虚拟机需要付出努力 关于回收未使用的物品 为了让他们的记忆 当前可用于快速访问 重新使用当控件从 方法调用,Java虚拟机 已尽最大努力收回 与所有丢弃对象之间的空间


似乎没有人明确地将对象引用设置为<代码> null <代码>,这是一个合法的“释放”你可能要考虑的内存的技术。

例如,假设您在一个方法开始时声明了一个
列表
,该列表的大小变得非常大,但仅在该方法进行到一半时才需要。此时,您可以将列表引用设置为
null
,以允许垃圾回收器在方法完成之前潜在地回收此对象(并且引用仍不在范围内)


请注意,我在现实中很少使用这种技术,但在处理非常大的数据结构时值得考虑。

如果您真的想分配和释放内存块,可以使用直接字节缓冲区。甚至还有一种不可移植的方式来释放内存

然而,正如所建议的,仅仅因为必须在C中释放内存,并不意味着必须这样做是一个好主意


如果您觉得free()确实有一个很好的用例,请将其包含在问题中,这样我们就可以看到您要做什么,很可能有更好的方法。

希望从任何程序(java或非java)中释放内存的一个有效原因是在操作系统级别上为其他程序提供更多内存。如果我的java应用程序使用的是250MB,我可能希望将其压缩到1MB,并使249MB可用于其他应用程序

在我的例子中,因为我的Java代码打算在不久的将来移植到其他语言(主要是C++),所以我至少想口头上说适当地释放内存,这样可以帮助以后的移植过程

我个人依赖于将变量置零作为将来正确删除的占位符。例如,在实际删除(使其为null)数组本身之前,我会花时间使数组的所有元素为null

但我的情况非常特殊,我知道这样做会影响性能。

*“例如,假设您在 方法的大小越来越大,但只需要 直到方法完成一半。此时,您可以设置 列出对null的引用,以允许垃圾收集器 在方法完成(和引用)之前回收此对象 无论如何都不在范围之内)。“*

这是正确的,但此解决方案可能无法推广。当将列表对象引用设置为null时,将使内存可用于垃圾收集,这仅适用于基元类型的列表对象。如果列表对象包含引用类型,则设置列表对象=
a -> x
a -> null
     x
a -> arr -> x
         -> y
         -> z
a -> null
     arr -> x
         -> y
         -> z
a -> null
     x
     y
     z
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
public static void main(String args[])
{
  // Instantiate a large memory using class
  MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192);

  // Do some work
  for ( .............. )
  {
      // Do some processing on myClass
  }

  // Clear reference to myClass
  myClass = null;

  // Continue processing, safe in the knowledge
  // that the garbage collector will reclaim myClass
}
System.gc();