如何在Java中释放内存?

有没有一种方法来释放Java中的内存,类似于C的free()函数? 或者是设置对象为空,并依靠GC唯一的select?

Java使用托pipe内存,所以分配内存的唯一方法是使用new运算符,并且可以取消分配内存的唯一方法是依靠垃圾回收器。

这个内存pipe理白皮书 (PDF)可能有助于解释发生了什么事情。

您也可以调用System.gc()来build议垃圾收集器立即运行。 但是,Java Runtime会做出最终决定,而不是您的代码。

根据Java文档 ,

调用gc方法表明,Java虚拟机花费大量的工作来回收未使用的对象,以便使其当前占用的内存可供快速重用。 当控制从方法调用返回时,Java虚拟机已尽最大努力从所有被丢弃的对象中回收空间。

没有人似乎已经明确提到将对象引用设置为null ,这是一个合法的技术来“释放”你可能要考虑的内存。

例如,假设你在一个方法开始的时候声明了一个List<String> ,这个方法的规模是非常大的,但是只有在方法中途才需要。 您可以在此处将List引用设置为null以允许垃圾收集器在方法完成之前潜在地回收该对象(并且引用不在范围之内)。

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

 System.gc(); 

运行垃圾收集器。

调用gc方法表明 ,Java虚拟机花费大量的工作来回收未使用的对象,以便使其当前占用的内存可供快速重用。 当控制从方法调用返回时,Java虚拟机已尽最大努力从所有被丢弃的对象中回收空间。

不build议。

编辑:我在2009年写了原始的回应。现在是2015年。

垃圾收集者在爪哇20多年来一直稳步上升。 此时,如果您手动调用垃圾收集器,则可能需要考虑其他方法:

  • 如果您在有限数量的机器上强制GC,那么可能有一个负载平衡点远离当前机器,等待它完成向连接的客户机提供服务,在挂起连接之后超时一段时间,然后很难 – 重新启动JVM。 这是一个可怕的解决scheme,但是如果你在看System.gc(),强制重启可能是一个可能的权宜之计。
  • 考虑使用不同的垃圾收集器。 例如,(过去六年中的新产品)G1采集器是一个低暂停模型; 它总体使用更多的CPU,但是最好永远不要强制执行。 由于服务器CPU现在几乎都有多个核心,所以这是一个真正的好的权衡。
  • 看看你的标志调优内存使用。 特别是在较新版本的Java中,如果没有那么多长期运行的对象,可以考虑在堆中增加newgen的大小。 newgen(年轻)是分配新对象的地方。 对于一个web服务器来说,为请求创build的所有东西都放在这里,如果这个空间太小,Java将花费额外的时间将对象升级到寿命较长的内存,在那里它们更加昂贵。 (如果newgen稍微小一些,你会付出代价的。)例如,在G1中:
    • XX:G1NewSizePercent(默认为5;可能无所谓)
    • XX:G1MaxNewSizePercent(默认为60;可能会提高)。
  • 考虑告诉垃圾收集器你不会有更长的停顿。 这将导致更频繁的GC运行,以允许系统保持其余的约束。 在G1中:
    • XX:MaxGCPauseMillis(默认为200)

*“我个人依靠零值variables作为将来正确删除的占位符,例如,在实际删除(使null)数组本身之前,我花时间去取消数组中的所有元素。

这是不必要的。 Java GC工作的方式是find没有对它们引用的对象,所以如果我有一个带有引用(=variables)的对象x指向它,GC将不会删除它,因为有一个引用到那个对象:

 a -> x 

如果你发生这种情况,

 a -> null x 

所以现在x没有指向它的引用,将被删除。 当你设置一个不同于x的对象时,会发生同样的事情。

所以如果你有一个引用对象x,y和z的数组arr和一个引用数组的variablesa,它看起来像这样:

 a -> arr -> x -> y -> z 

如果你发生这种情况,

 a -> null arr -> x -> y -> z 

所以GC发现arr没有对它的引用设置,并删除它,这给你这个结构:

 a -> null x y z 

现在GCfindx,y和z并删除它们。 否则数组中的每个引用都不会变得更好,它只会消耗代码中的CPU时间和空间(也就是说,这不会造成更多的伤害,GC仍然能够执行它应该的方式)。

想要从任何程序释放内存的一个合理的理由(java或没有)是为操作系统级别的其他程序提供更多的内存。 如果我的Java应用程序正在使用250MB,我可能想要强制它下降到1MB,使249MB可用于其他应用程序。

我已经做了这个实验。

它的确是System.gc(); 只build议运行Garage收集器。

但是调用System.gc(); 在将所有引用设置为null之后,

会提高性能和内存占用。

为了扩展Yiannis Xanthopoulos和Hot Licks的回答和评论(对不起,我还不能评论!),你可以像这个例子一样设置VM选项:

 -XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30 

在我的JDK 7中,如果超过30%的堆在GC空闲后GC变为空闲,那么这将释放未使用的VM内存。 您可能需要调整这些参数。

虽然我没有在下面的链接中看到它的强调,但请注意,一些垃圾收集器可能不遵守这些参数,默认情况下,Java可能会为您select其中一个,如果您碰巧拥有多个核心(因此上面的UseG1GC参数)。

VM参数

更新:对于java 1.8.0_73,我已经看到JVM偶尔使用默认设置释放less量数据。 看来只有在70%的堆没有被使用的时候才能做到这一点..不知道如果操作系统在物理内存不足的情况下是否会更积极的释放。

如果你真的想分配和释放一块内存,你可以用直接的ByteBuffers来完成。 甚至有一种不可移动的方式来释放内存。

但是,正如已经提出的那样,仅仅因为你必须用C语言释放内存,并不意味着必须这样做。

如果你觉得你真的有一个免费的()用例,请把它包括在问题中,这样我们可以看到你正在做的事情,很可能有一个更好的方法。

完全从javacoffeebreak.com/faq/faq0012.html

低优先级的线程自动为用户处理垃圾收集。 在空闲期间,线程可能被调用,并且它可以开始释放先前分配给Java中的对象的内存。 但不要担心 – 它不会删除你的对象!

当没有对象的引用时,对于垃圾回收器来说,这是一个公平的游戏。 而不是调用一些例程(比如C ++中的free),只需将对象的所有引用赋值为null,或者为引用赋予一个新的类。

例如:

 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(); 

垃圾收集器将尝试回收可用空间,并且应用程序可以继续执行,尽可能多地回收内存(内存碎片问题可能适用于某些平台)。

就我而言,由于我的Java代码在不久的将来会被移植到其他语言(主要是C ++),所以我至less要支付口头的费用来正确地释放内存,以便稍后帮助移植过程。

我个人依靠取消variables作为未来适当删除的占位符。 例如,在实际删除(生成null)数组本身之前,我花了时间来取消数组中的所有元素。

但是我的情况非常特别,而且我知道我在做这个时候会performance出色。

*“例如,假设你在一个方法开始的时候声明了一个List,这个方法的大小是非常大的,但是直到方法中途才被需要,你可以在这里设置List引用为null以允许垃圾收集器在方法完成之前潜在地回收这个对象(并且引用超出范围)。 *

这是正确的,但是这个解决scheme可能不是一般的。 虽然将List对象引用设置为null,将使垃圾回收可用,但这仅适用于基本types的List对象。 如果List对象包含引用types,则设置List对象= null将不引用任何包含在列表中的引用types。 在这种情况下,设置List对象= null将孤立所包含的引用types,其对象将不可用于垃圾收集,除非垃圾收集algorithm足够聪明以确定对象已被孤立。

通过Java提供了自动垃圾回收有时你会想知道有多大的对象是多less剩下。免费内存使用编程方式import java.lang;Runtime r=Runtime.getRuntime(); 使用mem1=r.freeMemory();获得内存值mem1=r.freeMemory(); 释放内存调用r.gc(); 方法并调用freeMemory()