如何释放Java中的内存?


146

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


151
好吧...让我们直接讲一件事。仅仅因为您认为某事是不好的做法,而不是鼓励某事去做,并不值得将其否决。这是一个明确而有效的问题,询问是否有一种方法可以在不依赖垃圾回收的情况下用Java释放内存。尽管可能不建议这样做,但通常没有用,也不是一个好主意,但您可能不知道在不了解Felix所知的情况下,在某些情况下可能不需要它。Felix甚至可能没有计划使用它。他可能只是想知道是否有可能。它绝不应该被否决。
丹尼尔·宾汉

7
为了澄清起见,这是针对任何对此表示反对的人-不一定是先前的评论。
丹尼尔·宾汉

Answers:


96

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

内存管理白皮书(PDF)可能有助于解释发生了什么。

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

根据Java文档

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


5
它确实迫使垃圾收集器运行。它不会强迫它释放内存,但是...
Pablo Santa Cruz

13
没有Pablo,它不会强制GC运行。
杰斯珀,

1
一个非常可靠的人告诉我,所有HotSpotVM的垃圾收集器都会System.gc()完全忽略。
爱斯科(Esko)2010年

1
在winXp上,java SE GC会运行每个System.gc()或几乎所有运行,但API文档无法保证。
teodozjan 2012年

2
@Pablo Santa Cruz您什么意思不释放内存?我只是在我的程序上对其进行了测试,似乎有泄漏并且ram使用率似乎稳定了?丹尼尔(Daniel)只是说这只是建议,那么每次我调用该方法时,使用的ram的百分比如何始终保持稳定。你们使我困惑。

65

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

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

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


8
如果您确实要在仅用于方法一部分的对象上进行大量工作,我建议也可以。您的方法过于编译,将方法分为前后部分,或对代码的前半部分使用块(后者对测试脚本更有用)
Peter Lawrey

5
将对象引用设置为null的地方很重要,这是从另一个寿命长的对象(或可能从静态var)引用它的地方。例如,如果您有一个由大对象组成的长寿命数组,并且停止使用这些对象之一,则应将数组引用设置为null,以使该对象可用于GC。
Hot Licks 2014年

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。)

1
在我自己的文章中发表评论,这通常什么都不做,而反复调用它会导致JVM变得不稳定和其他问题。它也可能会碰到你的狗;谨慎处理。
院长J,

1
我会特别强调“调用gc方法表明JVM扩展工作量”的“建议”部分
matt b

2
@ Jesper,Dean的回答是“建议”。实际上,他从方法的javadocs中发布了确切的文档...
matt b

2
@Software Monkey:是的,我可以编辑它。但是由于Dean J显然很活跃(仅在几分钟前发布),所以我认为请他这样做是有礼貌的。如果没有,我会回到这里进行编辑并删除我的评论。
Daniel Pryden 09年

1
我们也应该说为什么不建议这样做。如果JVM注意运行GC的“建议”,则几乎可以肯定会使您的应用程序运行速度变慢,可能会降低许多数量级!
斯蒂芬·C

11

*“我个人将空变量用作占位符以进行将来的适当删除。例如,在实际删除数组本身(使之为null)之前,我花了一些时间使数组的所有元素无效。”

这是不必要的。Java GC的工作方式是找到没有对其引用的对象,因此,如果我有一个带有引用(=变量)a的对象x指向它,则GC不会删除它,因为有一个引用到该对象:

a -> x

如果您将a设为null,则会发生这种情况:

a -> null
     x

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

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

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

如果您将a设为null,则会发生这种情况:

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

因此,GC发现arr没有设置引用,并将其删除,从而为您提供了以下结构:

a -> null
     x
     y
     z

现在,GC将找到x,y和z并将其删除。清空数组中的每个引用不会有任何改善,它只会占用代码中的CPU时间和空间(也就是说,它不会对此造成更大的损害。GC仍然可以执行应有的方式)。


5

想要从任何程序中释放内存的正确原因(是否为java)是为了使更多内存可用于操作系统级别的其他程序。如果我的Java应用程序正在使用250MB,则可能需要将其降低到1MB,并使249MB可用于其他应用程序。


如果您需要在Java程序中显式释放249MB的块,那么内存管理就不是我想要做的第一件事。
马克·迪米洛

3
但是(通常情况下)释放Java堆内部的存储不会使该存储可用于其他应用程序。
Hot Licks 2014年

5

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

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

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

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

VM参数

更新:对于Java 1.8.0_73,我已经看到JVM偶尔会使用默认设置释放少量内容。似乎只有在未使用约70%的堆时才这样做。.不知道如果操作系统的物理内存不足,是否会更积极地释放。


4

我已经对此做了实验。

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

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


我认为您不能肯定地说“将所有引用设置为null之后,调用System.gc();会提高性能和内存占用。”。因为System.gc()的计算复杂度很高。即使在调用System.gc()并确实收集了垃圾之后,jvm也可能不会将内存还给OS或System。JVM可能会保留内存以供将来参考。看到这个答案
阿布·纳菲·伊卜纳·扎希德(Abu Nafee)女士

3

如果您确实要分配和释放一块内存,则可以使用直接ByteBuffers来完成。甚至还有一种非便携式的方式来释放内存。

但是,正如已经建议的那样,仅仅因为您必须释放C语言中的内存,并不意味着必须这样做。

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


3

完全来自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();

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


1

就我而言,由于我的Java代码打算在不久的将来移植到其他语言(主要是C ++),所以我至少要付出口头服务才能正确释放内存,以便以后帮助移植过程。

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

但是我的案子很特别,我知道这样做会打击性能。


1

*“例如,假设您在方法的开头声明了一个List,该方法的大小变得非常大,但只需要在方法进行到一半时即可。此时,您可以将List引用设置为null以允许垃圾收集器在方法完成之前可能收回该对象(无论如何引用都超出范围)。” *

这是正确的,但是此解决方案可能无法推广。将List对象引用设置为null时,将使内存可用于垃圾回收,但这仅适用于基本类型的List对象。如果List对象包含引用类型,则将List对象设置为null不会取消引用列表中包含的任何引用类型。在这种情况下,将List object设置为null将孤立包含的引用类型,这些对象的对象不可用于垃圾回收,除非垃圾回收算法足够聪明,可以确定对象已被孤立。


1
这实际上是不正确的。Java垃圾收集器足够聪明,可以正确处理它。如果将列表为空(并且列表中的对象没有对其的其他引用),G​​C可以回收列表中的所有对象。它可能会选择暂时不这样做,但最终会收回它们。循环引用也是如此。基本上,GC的工作方式是先寻找orphraned对象,然后回收它们。这是GC的全部工作。您所描述的方式将使GC完全无用。
达卡龙2015年

1

g虽然Java提供了自动垃圾回收,有时你会想知道对象的大小以及使用编程是如何呢所剩无几。免费存储 import java.lang;Runtime r=Runtime.getRuntime(); 获得使用的内存值mem1=r.freeMemory();来释放内存调用的r.gc();方法和呼叫freeMemory()


1

JAVA建议将其分配为null

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

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

应用程序可能不释放对象引用而导致内存泄漏。这样做会阻止Java垃圾回收器回收这些对象,并导致使用的内存量增加。使用变量后,显式取消对变量的引用可以使垃圾回收器回收内存。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.