如何在 Java 中释放内存?

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

248441 次浏览
System.gc();

管理垃圾收集器。

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

不推荐。

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

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

  • 如果要在有限的机器上强制执行 GC,那么从当前机器上设置一个负载平衡点 离开,等待它完成对已连接客户机的服务,在挂起连接一段时间后超时,然后硬重新启动 JVM,这样做可能是值得的。这是一个糟糕的解决方案,但是如果您正在查看 System.gc () ,强制重启可能是一个可能的权宜之计。
  • 考虑使用不同的垃圾收集器。例如,(最近六年才出现的) G1收集器是一个低暂停模型; 它总体上使用了更多的 CPU,但是最好不要强制执行硬停止。由于服务器 CPU 现在几乎都有多个核,这是一个非常好的折衷可用。
  • 查看调优内存使用的标志。特别是在 Java 的新版本中,如果没有那么多长期运行的对象,可以考虑在堆中增加 newgen 的大小。Newgen (young)是分配新对象的地方。对于 web 服务器,为请求创建的所有内容都放在这里,如果这个空间太小,Java 将花费额外的时间将对象升级到更长的内存,在那里它们更加昂贵。(如果 newgen 有点太小,你就要付钱。)例如,在 G1中:
    • XX: G1NewSizePercent (默认为5; 可能无关紧要)
    • XX: G1MaxNewSizePercent (默认为60; 可能提高此值)
  • 考虑告诉垃圾收集器你不能接受更长的暂停时间。这将导致更频繁的 GC 运行,从而允许系统保留其余的约束。在 G1:
    • XX: MaxGCPauseMillis (默认为200)

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

这个 内存管理白皮书(PDF)可能有助于解释正在发生的事情。

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

根据 Java 文档,

调用 gc 方法表明 Java 虚拟机的努力 回收未使用的物品 为了使他们的记忆 目前可用于快速 控件从 方法调用,Java 虚拟机 已经尽了最大的努力 来自所有被丢弃的物体的空间。

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

例如,假设您在一个方法的开头声明了一个 List<String>,这个方法的大小变得非常大,但是只需要声明到方法执行到一半的时候。此时,您可以将 List 引用设置为 null,以允许垃圾回收器在方法完成之前可能回收此对象(而且该引用无论如何都不在作用域范围内)。

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

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

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

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

想要从任何程序(不管是不是 java)中释放内存的一个合理的原因是为操作系统级别的其他程序提供更多的内存。如果我的 java 应用程序使用250MB,我可能会强制它下降到1MB,并使249MB 可用于其他应用程序。

在我的案例中,由于我的 Java 代码将在不久的将来被移植到其他语言(主要是 C + +) ,我至少想在口头上正确地释放内存,以便在以后帮助移植过程。

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

但我的情况是非常特殊的,我知道我在这样做的时候会受到性能的影响。

*”例如,假设您在一个 这种方法的规模越来越大,但只需要 直到方法执行到一半为止 对 null 的列表引用,以允许垃圾回收器潜在地 在方法完成之前回收此对象(以及引用 无论如何都不在范围之内)。”

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

* “我个人依赖于空变量作为占位符,以便将来进行适当删除。例如,在实际删除(使其为空)数组本身之前,我会花时间使数组的所有元素为空。”

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

a -> x

如果 a 为空,就会发生这种情况:

a -> null
x

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

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

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

如果 a 为空,就会发生这种情况:

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

所以 GC 会发现 arr 没有设置引用,然后删除它,这样就得到了这样的结构:

a -> null
x
y
z

现在 GC 找到 x,y 和 z 并删除它们。取消数组中的每个引用不会有任何好处,它只会占用代码中的 CPU 时间和空间(也就是说,不会造成更大的损失。)。GC 仍然能够按照它应该的方式执行)。

我在这上面做过实验。

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

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

延伸的答案和评论由 Yiannis Xanthopoulos 和热舔(对不起,我还不能评论!),您可以像下面的例子一样设置 VM 选项:

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

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

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

VM 参数

更新: 对于 java 1.8.0 _ 73,我看到 JVM 偶尔使用默认设置发布少量内容。不过,似乎只有在堆中约70% 未使用时才会这样做。.不知道如果操作系统的物理内存不足,释放会不会更激进。

尽管 java 提供了自动垃圾收集功能,但是有时候你会想知道对象有多大,还剩下多少。释放内存使用程序化的 import java.lang;Runtime r=Runtime.getRuntime();来获取内存值使用 mem1=r.freeMemory();来释放内存调用的 r.gc();方法和 freeMemory()调用

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

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

当没有对象的引用时,对于 而不是调用一些例程(比如 free in 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();

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

JAVA 的建议是赋值为 null

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

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

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

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