如何在Java中释放内存?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1567979/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to free memory in Java?
提问by Felix
Is there a way to free memory in Java, similar to C's free()
function? Or is setting the object to null and relying on GC the only option?
有没有办法在Java中释放内存,类似于C的free()
功能?还是将对象设置为 null 并依赖 GC 是唯一的选择?
采纳答案by Daniel Pryden
Java uses managed memory, so the only way you can allocate memory is by using the new
operator, and the only way you can deallocate memory is by relying on the garbage collector.
Java 使用托管内存,因此分配内存的唯一方法是使用new
运算符,而释放内存的唯一方法是依赖垃圾收集器。
This memory management whitepaper(PDF) may help explain what's going on.
此内存管理白皮书(PDF) 可能有助于解释正在发生的事情。
You can also call System.gc()
to suggest that the garbage collector run immediately. However, the Java Runtime makes the final decision, not your code.
你也可以打电话System.gc()
建议垃圾收集器立即运行。但是,最终决定的是 Java 运行时,而不是您的代码。
According to the Java documentation,
根据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.
调用 gc 方法表明 Java 虚拟机花费精力来回收未使用的对象,以使它们当前占用的内存可用于快速重用。当控制从方法调用返回时,Java 虚拟机已尽最大努力从所有丢弃的对象中回收空间。
回答by Dean J
System.gc();
Runs the garbage collector.
Calling the gc method suggeststhat 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.
运行垃圾收集器。
调用 gc 方法表明Java 虚拟机花费精力来回收未使用的对象,以使它们当前占用的内存可用于快速重用。当控制从方法调用返回时,Java 虚拟机已尽最大努力从所有丢弃的对象中回收空间。
Not recommended.
不建议。
Edit: I wrote the original response in 2009. It's now 2015.
编辑:我在 2009 年写了原始回复。现在是 2015 年。
Garbage collectors have gotten steadily better in the ~20 years Java's been around. At this point, if you're manually calling the garbage collector, you may want to consider other approaches:
在 Java 出现的大约 20 年里,垃圾收集器已经变得越来越好。此时,如果您手动调用垃圾收集器,您可能需要考虑其他方法:
- If you're forcing GC on a limited number of machines, it may be worth having a load balancer point awayfrom the current machine, waiting for it to finish serving to connected clients, timeout after some period for hanging connections, and then just hard-restart the JVM. This is a terrible solution, but if you're looking at System.gc(), forced-restarts may be a possible stopgap.
- Consider using a different garbage collector. For example, the (new in the last six years) G1 collector is a low-pause model; it uses more CPU overall, but does it's best to never force a hard-stop on execution. Since server CPUs now almost all have multiple cores, this is A Really Good Tradeoff to have available.
- Look at your flags tuning memory use. Especially in newer versions of Java, if you don't have that many long-term running objects, consider bumping up the size of newgen in the heap. newgen (young) is where new objects are allocated. For a webserver, everything created for a request is put here, and if this space is too small, Java will spend extra time upgrading the objects to longer-lived memory, where they're more expensive to kill. (If newgen is slightly too small, you're going to pay for it.) For example, in G1:
- XX:G1NewSizePercent (defaults to 5; probably doesn't matter.)
- XX:G1MaxNewSizePercent (defaults to 60; probably raise this.)
- Consider telling the garbage collector you're not okay with a longer pause. This will cause more-frequent GC runs, to allow the system to keep the rest of it's constraints. In G1:
- XX:MaxGCPauseMillis (defaults to 200.)
- 如果您在有限数量的机器上强制执行 GC,可能值得让负载平衡器远离当前机器,等待它完成为连接的客户端提供服务,在挂起连接一段时间后超时,然后就很难了-重新启动JVM。这是一个糟糕的解决方案,但如果您正在查看 System.gc(),强制重启可能是一个可能的权宜之计。
- 考虑使用不同的垃圾收集器。例如,(最近六年新推出的)G1 收藏家是一个低暂停模型;它总体上使用更多的 CPU,但最好不要强制执行硬停止。由于服务器 CPU 现在几乎都有多个内核,因此这是一个非常好的折衷方案。
- 查看您的标志调整内存使用情况。特别是在较新版本的 Java 中,如果您没有那么多长期运行的对象,请考虑增加堆中 newgen 的大小。newgen(年轻)是分配新对象的地方。对于网络服务器,为请求创建的所有内容都放在这里,如果这个空间太小,Java 将花费额外的时间将对象升级到寿命更长的内存,在那里杀死它们的成本更高。(如果 newgen 有点太小,你会为此付出代价。)例如,在 G1 中:
- XX:G1NewSizePercent(默认为 5;可能无关紧要。)
- XX:G1MaxNewSizePercent(默认为 60;可能会提高这个值。)
- 考虑告诉垃圾收集器你不能接受更长的停顿。这将导致更频繁的 GC 运行,以允许系统保留其余的约束。在 G1 中:
- XX:MaxGCPauseMillis(默认为 200。)
回答by Adamski
No one seems to have mentioned explicitly setting object references to null
, which is a legitimate technique to "freeing" memory you may want to consider.
似乎没有人提到明确地将对象引用设置为null
,这是您可能想要考虑的“释放”内存的合法技术。
For example, say you'd declared a List<String>
at the beginning of a method which grew in size to be very large, but was only required until half-way through the method. You could at this point set the List reference to null
to allow the garbage collector to potentially reclaim this object before the method completes (and the reference falls out of scope anyway).
例如,假设您List<String>
在一个方法开始时声明了 a ,该方法的大小变得非常大,但仅在该方法进行到一半时才需要。此时,您可以将 List 引用设置null
为允许垃圾收集器在方法完成之前潜在地回收此对象(并且该引用无论如何都超出了范围)。
Note that I rarely use this technique in reality but it's worth considering when dealing with very large data structures.
请注意,我在现实中很少使用这种技术,但在处理非常大的数据结构时值得考虑。
回答by Peter Lawrey
If you really want to allocate and free a block of memory you can do this with direct ByteBuffers. There is even a non-portable way to free the memory.
如果你真的想分配和释放一块内存,你可以使用直接的 ByteBuffers 来做到这一点。甚至有一种非便携式的方式来释放内存。
However, as has been suggested, just because you have to free memory in C, doesn't mean it a good idea to have to do this.
但是,正如所建议的,仅仅因为您必须在 C 中释放内存,并不意味着必须这样做是个好主意。
If you feel you really have a good use case for free(), please include it in the question so we can see what you are rtying to do, it is quite likely there is a better way.
如果你觉得你真的有一个很好的 free() 用例,请将它包含在问题中,以便我们可以看到你想要做什么,很可能有更好的方法。
回答by Yios
A valid reason for wanting to free memory from any programm (java or not ) is to make more memory available to other programms on operating system level. If my java application is using 250MB I may want to force it down to 1MB and make the 249MB available to other apps.
想要从任何程序(java 与否)中释放内存的一个正当理由是在操作系统级别为其他程序提供更多内存。如果我的 java 应用程序使用 250MB,我可能想将其强制降低到 1MB,并使 249MB 可用于其他应用程序。
回答by Oskuro
In my case, since my Java code is meant to be ported to other languages in the near future (Mainly C++), I at least want to pay lip service to freeing memory properly so it helps the porting process later on.
就我而言,由于我的 Java 代码打算在不久的将来移植到其他语言(主要是 C++),我至少想口头上正确释放内存,以便它有助于以后的移植过程。
I personally rely on nulling variables as a placeholder for future proper deletion. For example, I take the time to nullify all elements of an array before actually deleting (making null) the array itself.
我个人依赖清零变量作为未来正确删除的占位符。例如,在实际删除(使空)数组本身之前,我花时间使数组的所有元素无效。
But my case is very particular, and I know I'm taking performance hits when doing this.
但是我的情况非常特殊,我知道这样做会影响性能。
回答by Gothri
* "For example, say you'd declared a List at the beginning of a method which grew in size to be very large, but was only required until half-way through the method. You could at this point set the List reference to null to allow the garbage collector to potentially reclaim this object before the method completes (and the reference falls out of scope anyway)." *
* "例如,假设您在一个方法开始时声明了一个 List,该方法的大小变得非常大,但仅在该方法进行到一半时才需要。此时您可以将 List 引用设置为 null允许垃圾收集器在方法完成之前潜在地回收这个对象(并且引用无论如何都超出了范围)。” *
This is correct, but this solution may not be generalizable. While setting a List object reference to null -will- make memory available for garbage collection, this is only true for a List object of primitive types. If the List object instead contains reference types, setting the List object = null will not dereference -any- of the reference types contained -in- the list. In this case, setting the List object = null will orphan the contained reference types whose objects will not be available for garbage collection unless the garbage collection algorithm is smart enough to determine that the objects have been orphaned.
这是正确的,但此解决方案可能无法推广。将 List 对象引用设置为 null -将使内存可用于垃圾收集,这仅适用于原始类型的 List 对象。如果 List 对象包含引用类型,则设置 List object = null 将不会取消引用列表中包含的任何引用类型。在这种情况下,设置 List object = null 将孤立包含的引用类型,其对象将不可用于垃圾收集,除非垃圾收集算法足够智能来确定对象已被孤立。
回答by Dakkaron
*"I personally rely on nulling variables as a placeholder for future proper deletion. For example, I take the time to nullify all elements of an array before actually deleting (making null) the array itself."
*“我个人依赖空变量作为占位符以便将来正确删除。例如,在实际删除(使空)数组本身之前,我花时间使数组的所有元素无效。”
This is unnecessary. The way the Java GC works is it finds objects that have no reference to them, so if I have an Object x with a reference (=variable) a that points to it, the GC won't delete it, because there is a reference to that object:
这是不必要的。Java GC 的工作方式是找到没有对它们的引用的对象,所以如果我有一个带有指向它的引用 (=variable) a 的对象 x,GC 不会删除它,因为有一个引用到那个对象:
a -> x
If you null a than this happens:
如果您将 a 设为 null,则会发生以下情况:
a -> null
x
So now x doesn't have a reference pointing to it and will be deleted. The same thing happens when you set a to reference to a different object than x.
所以现在 x 没有指向它的引用,将被删除。当您将 a 设置为对与 x 不同的对象的引用时,会发生同样的事情。
So if you have an array arr that references to objects x, y and z and a variable a that references to the array it looks like that:
因此,如果您有一个引用对象 x、y 和 z 的数组 arr 和一个引用该数组的变量 a ,它看起来像这样:
a -> arr -> x
-> y
-> z
If you null a than this happens:
如果您将 a 设为 null,则会发生以下情况:
a -> null
arr -> x
-> y
-> z
So the GC finds arr as having no reference set to it and deletes it, which gives you this structure:
因此,GC 发现 arr 没有对其设置引用并删除它,这为您提供了以下结构:
a -> null
x
y
z
Now the GC finds x, y and z and deletes them aswell. Nulling each reference in the array won't make anything better, it will just use up CPU time and space in the code (that said, it won't hurt further than that. The GC will still be able to perform the way it should).
现在 GC 找到 x、y 和 z 并删除它们。清空数组中的每个引用不会让任何事情变得更好,它只会消耗代码中的 CPU 时间和空间(也就是说,它不会比这更糟糕。GC 仍然能够按照它应该的方式执行)。
回答by Hemant Yadav
I have done experimentation on this.
我已经对此进行了实验。
It's true that System.gc();
only suggests to run the Garbage Collector.
确实,System.gc();
只建议运行垃圾收集器。
But calling System.gc();
after setting all references to null
, will improve performance and memory occupation.
但是System.gc();
在将所有引用设置为 后调用null
,会提高性能和内存占用。
回答by nsandersen
To extend upon the answer and comment by Yiannis Xanthopoulos and Hot Licks (sorry, I cannot comment yet!), you can set VM options like this example:
为了扩展 Yiannis Xanthopoulos 和 Hot Licks 的回答和评论(抱歉,我还不能发表评论!),您可以像下面这样设置 VM 选项:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
In my jdk 7 this will then release unused VM memory if more than 30% of the heap becomes free after GC when the VM is idle. You will probably need to tune these parameters.
在我的 jdk 7 中,如果在 VM 空闲时超过 30% 的堆在 GC 后空闲,这将释放未使用的 VM 内存。您可能需要调整这些参数。
While I didn't see it emphasized in the link below, note that some garbage collectors may not obey these parameters and by default java may pick one of these for you, should you happen to have more than one core (hence the UseG1GC argument above).
虽然我没有在下面的链接中看到强调它,但请注意,某些垃圾收集器可能不遵守这些参数,并且默认情况下,java 可能会为您选择其中之一,如果您碰巧有多个核心(因此上面的 UseG1GC 参数) )。
Update: For java 1.8.0_73 I have seen the JVM occasionally release small amounts with the default settings. Appears to only do it if ~70% of the heap is unused though.. don't know if it would be more aggressive releasing if the OS was low on physical memory.
更新:对于 java 1.8.0_73,我看到 JVM 偶尔会使用默认设置释放少量。似乎只有在大约 70% 的堆未使用的情况下才会这样做.. 不知道如果操作系统的物理内存不足,它是否会更积极地释放。