java中关于垃圾收集_关于垃圾收集:如何在Java中释放内存?

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

好的......让我们直截了当。 仅仅因为你认为某些事情是不好的做法而不是鼓励做的事情,并不值得投票。 这是一个明确而有效的问题,询问是否有办法在Java中释放内存而不依赖于垃圾收集。 虽然它可能是气馁的,通常没用或者不是一个好主意,但你无法知道在没有菲利克斯知道的情况下可能不需要它的情况。 菲利克斯甚至可能没有计划使用它。 他可能只想知道是否可能。 它绝不值得投票。

为了澄清,这是针对任何投票的人 - 不是之前的评论。

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

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

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

根据Java文档,

Calling the gc method suggests that

the Java Virtual Machine expend effort

toward recycling unused objects in

order to make the memory they

currently occupy available for quick

reuse. When control returns from the

method call, the Java Virtual Machine

has made a best effort to reclaim

space from all discarded objects.

它确实强制垃圾收集器运行。虽然它不会强迫它释放内存......

没有Pablo,它不会强制GC运行。

好。我知道了。感谢您指出了这一点。

谢谢,第一段几乎是我想知道的。谢谢你澄清一切,是的,我明白了,我不会使用System.gc():)

一位非常可靠的人告诉我,所有HotSpotVM的垃圾收集器都完全忽略System.gc()。

在winXp上,java SE GC运行每个System.gc()或几乎所有API文档都不保证它。

@Pablo Santa Cruz你的意思是什么它不释放内存?我只是在我的程序上测试了它似乎有泄漏并且ram使用似乎稳定了?但丹尼尔只是说它只是暗示了为什么每次调用这种方法时,使用的ram百分比总是稳定下来。你们让我很困惑。

@Esko,曾经告诉过你,似乎从来没有在Java应用程序中完成内存分析。确实不会在每次拨打电话时都运行GC,但我绝对肯定它并不是简单地忽略它。

如果从Visual VM强制GC,它是否等同于调用System#gc?

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

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

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

如果你真的在一个对象上做了很多工作,这个对象只用于我建议的方法的一部分;你的方法过于复杂,将方法分解为前后部分,或者对前半部分代码使用一个块(后者对于测试脚本更有用)

将对象引用设置为null很重要的地方是从另一个长期存在的对象(或者可能来自静态var)引用它。例如,如果您有一个长期存在的大型对象数组,并且停止使用其中一个对象,则应将数组引用设置为null以使该对象可用于GC。

System.gc();

Runs the garbage collector.

Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.

不建议。

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

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

如果你在有限数量的机器上强制使用GC,那么可能值得让负载平衡器远离当前机器,等待它完成为连接的客户端服务,在一段时间后暂停连接超时,然后再努力-restart JVM。这是一个糟糕的解决方案,但如果您正在查看System.gc(),强制重启可能是一个可能的权宜之计。

考虑使用不同的垃圾收集器。例如,(过去六年中的新)G1收集器是一个低暂停模型;它总体上使用了更多的CPU,但是最好永远不要强制执行硬件。由于服务器CPU现在几乎都拥有多个内核,因此这是一个非常好的权衡。

看看调整内存使用的标志。特别是在较新版本的Java中,如果没有那么多长期运行的对象,请考虑增加堆中newgen的大小。 newgen(年轻)是分配新对象的地方。对于Web服务器,为请求创建的所有内容都放在此处,如果此空间太小,Java将花费额外的时间将对象升级到更长寿的内存,在这些内存中它们的销售成本更高。 (如果newgen稍微太小,你就要付钱了。)例如,在G1中:

XX:G1NewSizePercent(默认为5;可能无关紧要。)

XX:G1MaxNewSizePercent(默认为60;可能会提高此值。)

考虑告诉垃圾收集器你没有时间更长的停顿。这将导致更频繁的GC运行,以允许系统保持其余的约束。在G1:

XX:MaxGCPauseMillis(默认为200.)

评论我自己的帖子,这通常不会做任何事情,反复调用它会导致JVM变得不稳定等等。它也可能会掠过你的狗;谨慎对待。

我会高度重视"调用gc方法表明JVM扩展努力"的"建议"部分

另请注意,单次调用System.gc()通常只会收集一点垃圾。要收集所有内容,您需要在循环中调用它,使用Runtime.freeMemory()监视可用内存量何时不再增加。但是确实很少需要调用System.gc()。一个有用的情况是当你试图测量内存消耗时,因为在中间运行GC会使测量结果变得混乱。

@Jesper,Dean的回答说"建议"。事实上,他发布了方法的javadocs中的确切文档......

@Dean J:你可能想要阻止你的文本,以明确你直接从Java文档中引用。

@Daniel:不要在评论中告诉他,只需自己编辑答案并添加所需的单个">"就会更快更有用。

固定,因为我剪切和粘贴的所有东西都不是以前的块引用。

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

我们也值得一说,为什么不推荐这样做。如果JVM关注运行GC的"建议",它几乎肯定会使你的应用程序运行速度变慢,可能需要多个数量级!

根据反馈,我也加粗了SUGGESTS。希望现在更清楚了。

提示与否,我观察到GC运行得非常快,因为"建议"发生并且垃圾收集器运行。我正在使用System.gc()用于Android游戏,并且考虑到VM上的小型典型堆大小,手动调用它实际上有助于加载位图或长音频剪辑。

*"我个人依赖于将变量归零作为占位符以便将来正确删除。例如,在实际删除(使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仍然可以执行它应该的方式)。

为了扩展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%的堆未被使用的情况下才会这样做..如果操作系统的物理内存不足,不知道它是否会更积极地释放。

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

如果你需要在Java程序中明确地释放一块249MB的内存,那么内存管理将不是我想要处理的第一件事。

但是,释放Java堆中的存储空间(通常情况下)不会使存储可供其他应用程序使用。

我已经做过实验。

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

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

我认为你不能肯定地说"调用System.gc();在设置所有引用为null之后,将提高性能和内存占用。" 因为System.gc()存在巨大的计算复杂性。 即使在调用System.gc()并确实收集垃圾之后,jvm也可能无法将内存返回给操作系统或系统。 JVM可以保留内存以供将来参考。 看到这个答案。

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

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

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

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

A low priority thread takes care of garbage collection automatically

for the user. During idle time, the thread may be called upon, and it

can begin to free memory previously allocated to an object in Java.

But don't worry - it won't delete your objects on you!

When there are no references to an object, it becomes fair game for

the garbage collector. Rather than calling some routine (like free in

C++), you simply assign all references to the object to null, or

assign a new class to the reference.

Example :

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

}

If your code is about to request a large amount of memory, you may

want to request the garbage collector begin reclaiming space, rather

than allowing it to do so as a low-priority thread. To do this, add

the following to your code

System.gc();

The garbage collector will attempt to reclaim free space, and your

application can continue executing, with as much memory reclaimed as

possible (memory fragmentation issues may apply on certain platforms).

JAVA的建议是指定为null

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

Explicitly assigning a null value to variables that are no longer needed helps the garbage collector to identify the parts of memory that can be safely reclaimed. Although Java provides memory management, it does not prevent memory leaks or using excessive amounts of memory.

An application may induce memory leaks by not releasing object references. Doing so prevents the Java garbage collector from reclaiming those objects, and results in increasing amounts of memory being used. Explicitly nullifying references to variables after their use allows the garbage collector to reclaim memory.

One way to detect memory leaks is to employ profiling tools and take memory snapshots after each transaction. A leak-free application in steady state will show a steady active heap memory after garbage collections.

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

*"例如,假设您在一个开头宣布了一个列表

增长的方法非常大,但只需要

直到该方法的中途。你可以在这一点上设置

列出对null的引用以允许垃圾收集器潜在地

在方法完成之前回收此对象(和引用

不管怎样都超出了范围。"*

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

事实并非如此。 Java垃圾收集器非常智能,可以正确处理。 如果使列为空(并且列表中的对象没有对它们的其他引用),则GC可以回收列表中的所有对象。 它可能选择在目前不这样做,但最终会收回它们。 循环引用也是如此。 基本上,GC的工作方式是明确地寻找orphraned对象,然后回收它们。 这是GC的全部工作。 你描述它的方式会让GC完全没用。

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值