如何在Java中释放内存?

时间:2009-10-14 17:58:57

标签: java garbage-collection

有没有办法在Java中释放内存,类似于C的free()函数?或者将对象设置为null并依赖GC是唯一的选择?

13 个答案:

答案 0 :(得分:90)

Java使用托管内存,因此分配内存的唯一方法是使用new运算符,并且释放内存的唯一方法是依赖垃圾收集器。

memory management whitepaper(PDF)可能有助于解释正在发生的事情。

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

根据Java documentation

  

调用gc方法表明了这一点   Java虚拟机花费精力   回收未使用的物品   为了使他们记忆   目前可以快速占用   重用。当控制从中返回时   方法调用,Java虚拟机   我已尽最大努力收回   所有丢弃物体的空间。

答案 1 :(得分:62)

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

例如,假设您在方法的开头声明了List<String>,该方法的大小变得非常大,但只在该方法的中途才需要。此时,您可以将List引用设置为null,以允许垃圾收集器在方法完成之前可能回收此对象(并且引用无论如何都会超出范围)。

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

答案 2 :(得分:22)

System.gc(); 
  

运行垃圾收集器。

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

不推荐。

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

垃圾收集器在Java已经存在的约20年里变得越来越好。此时,如果您手动调用垃圾收集器,您可能需要考虑其他方法:

  • 如果您在有限数量的计算机上强制执行GC,则可能需要从当前计算机上将负载平衡器指向,等待它完成为连接的客户端提供服务,之后超时挂起连接的一段时间,然后只需硬重启JVM。这是一个糟糕的解决方案,但如果您正在查看System.gc(),强制重启可能是一种可能的权宜之计。
  • 考虑使用不同的垃圾收集器。例如,(过去六年中的新)G1收集器是一个低暂停模型;它总体上使用了更多的CPU,但是最好永远不要强制执行硬件。由于服务器CPU现在几乎都具有多个内核,因此这是一个非常好的权衡。
  • 查看调整内存使用的标志。特别是在较新版本的Java中,如果没有那么多长期运行的对象,请考虑增加堆中newgen的大小。 newgen(年轻)是分配新对象的地方。对于Web服务器,为请求创建的所有内容都放在此处,如果此空间太小,Java将花费额外的时间将对象升级到更长寿的内存,在这些内存中它们的销售成本更高。 (如果newgen稍微太小,你就要付钱了。)例如,在G1中:
    • XX:G1NewSizePercent(默认为5;可能无关紧要。)
    • XX:G1MaxNewSizePercent(默认为60;可能会提高此值。)
  • 考虑告诉垃圾收集器你没有时间更长的停顿。这将导致更频繁的GC运行,以允许系统保持其余的约束。在G1:
    • XX:MaxGCPauseMillis(默认为200。)

答案 3 :(得分:11)

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

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

a -> x

如果你为null,则发生这种情况:

a -> null
     x

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

因此,如果您有一个引用对象x,y和z的数组arr以及一个引用该数组的变量a,它看起来就像:

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

如果你为null,则发生这种情况:

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

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

a -> null
     x
     y
     z

现在GC找到x,y和z并删除它们。取消数组中的每个引用都不会有更好的效果,它只会占用代码中的CPU时间和空间(也就是说,它不会比这更糟糕.GC仍然可以执行它应该的方式)。

答案 4 :(得分:5)

想要从任何程序(java或不是java)释放内存的正当理由是在操作系统级别为其他程序提供更多内存。如果我的java应用程序使用250MB,我可能希望将其强制降至1MB,并将249MB提供给其他应用程序。

答案 5 :(得分:5)

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

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

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

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

VM arguments

更新:对于java 1.8.0_73,我看到JVM偶尔会使用默认设置释放少量数据。似乎只有在大约70%的堆未被使用的情况下才会这样做。但是如果操作系统的物理内存不足,不知道它是否会更积极地释放。

答案 6 :(得分:4)

我已经做过实验。

System.gc();只建议运行垃圾收集器。

但在设置System.gc();的所有引用后调用null将提高性能和内存占用。

答案 7 :(得分:3)

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

然而,正如所建议的那样,仅仅因为你必须在C中释放内存,并不意味着必须这样做。

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

答案 8 :(得分:2)

完全来自javacoffeebreak.com/faq/faq0012.html

  

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

     

当没有对象的引用时,它就变成了公平的游戏   垃圾收集器。而不是调用一些例程(比如免费)   C ++),您只需将对象的所有引用分配为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();
     

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

答案 9 :(得分:1)

在我的情况下,由于我的Java代码意味着在不久的将来移植到其他语言(主要是C ++),我至少想要口头上的服务来正确释放内存,以便以后有助于移植过程。 / p>

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

但是我的情况非常特别,而且我知道在这样做的时候我会受到性能上的打击。

答案 10 :(得分:1)

*“例如,假设你在一个开头宣布了一个List 增长的方法非常大,但只需要 直到该方法的中途。你可以在这一点上设置 列出对null的引用以允许垃圾收集器潜在地 在方法完成之前回收此对象(和引用 无论如何都不属于范围。“*

这是正确的,但这种解决方案可能无法推广。将List对象引用设置为null -will- make memory可用于垃圾回收时,这仅适用于基本类型的List对象。如果List对象改为包含引用类型,则设置List object = null将不会取消引用列表中包含的引用类型。在这种情况下,设置List object = null将孤立包含的引用类型,其对象将无法用于垃圾回收,除非垃圾收集算法足够智能以确定对象已被孤立。

答案 11 :(得分:1)

Althrough java提供了自动垃圾收集,有时您会想知道对象有多大以及剩余多少。使用编程import java.lang;Runtime r=Runtime.getRuntime();使用{获取内存值来获取内存值{1}}释放内存会调用mem1=r.freeMemory();方法和调用r.gc();

答案 12 :(得分:1)

JAVA的建议是指定为空

来自https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html

  

为不再需要的变量显式分配空值有助于垃圾收集器识别可以安全回收的内存部分。尽管Java提供了内存管理,但它并不能防止内存泄漏或使用过多的内存。

     

应用程序可能会因未释放对象引用而导致内存泄漏。这样做可以防止Java垃圾收集器回收这些对象,并导致使用的内存量不断增加。使用后对变量的引用显式无效允许垃圾回收器回收内存。

     

检测内存泄漏的一种方法是在每次事务后使用分析工具并获取内存快照。处于稳定状态的无泄漏应用程序将在垃圾收集后显示稳定的活动堆内存。