Pet*_*rch 52 java memory-management heap-memory
我们有一个长期存在的服务器进程,很快就需要大量的RAM.我们看到,一旦JVM从操作系统获得内存,它就永远不会将其返回给操作系统.我们如何要求JVM将堆内存返回给操作系统?
通常,这些问题的接受答案是使用
-XX:MaxHeapFreeRatio
和-XX:MinHeapFreeRatio
.(参见例如
1,2,3,4).但是我们像这样运行java:
java -Xmx4G -XX:MaxHeapFreeRatio=50 -XX:MinHeapFreeRatio=30 MemoryUsage
Run Code Online (Sandbox Code Playgroud)
仍然在VisualVM中看到这个:
显然,JVM并不尊重,-XX:MaxHeapFreeRatio=50
因为heapFreeRatio非常接近100%而且远不及50%.无需点击"执行GC"即可将内存返回给操作系统.
MemoryUsage.java:
import java.util.ArrayList;
import java.util.List;
public class MemoryUsage {
public static void main(String[] args) throws InterruptedException {
System.out.println("Sleeping before allocating memory");
Thread.sleep(10*1000);
System.out.println("Allocating/growing memory");
List<Long> list = new ArrayList<>();
// Experimentally determined factor. This gives approximately 1750 MB
// memory in our installation.
long realGrowN = 166608000; //
for (int i = 0 ; i < realGrowN ; i++) {
list.add(23L);
}
System.out.println("Memory allocated/grown - sleeping before Garbage collecting");
Thread.sleep(10*1000);
list = null;
System.gc();
System.out.println("Garbage collected - sleeping forever");
while (true) {
Thread.sleep(1*1000);
}
}
}
Run Code Online (Sandbox Code Playgroud)
版本:
> java -version
openjdk version "1.8.0_66-internal"
OpenJDK Runtime Environment (build 1.8.0_66-internal-b01)
OpenJDK 64-Bit Server VM (build 25.66-b01, mixed mode)
> uname -a
Linux londo 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt11-1+deb8u5 (2015-10-09) x86_64 GNU/Linux
> lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 8.2 (jessie)
Release: 8.2
Codename: jessie
Run Code Online (Sandbox Code Playgroud)
我也尝试过OpenJDK 1.7和Sun Java 1.8.所有行为都相似,没有一个给内存回OS.
我确实认为我需要这个并且交换和分页不会"解决"这个问题,因为在寻呼上花费磁盘IO接近2GB的垃圾进出只会浪费资源.如果您不同意,请赐教.
我还用malloc()
/ 写了一点memoryUsage.c free()
,它确实将内存返回给操作系统.所以在C中是可能的.也许不是用Java?
编辑:奥古斯托指出,搜索会一直带领我-XX:MaxHeapFreeRatio
和-XX:MinHeapFreeRatio
只与合作-XX:+UseSerialGC
.我欣喜若狂,尝试了一下,感到困惑的是我自己没有找到这个.是的,它确实适用于我的MemoryUsage.java:
但是,当我尝试-XX:+UseSerialGC
使用我们的真实应用程序时,并非如此:
我发现gc()一段时间后确实有所帮助,所以我创建了一个或多或少的线程:
while (idle() && memoryTooLarge() && ! tooManyAttemptsYet()) {
Thread.sleep(10*1000);
System.gc();
}
Run Code Online (Sandbox Code Playgroud)
这就是诀窍:
实际上,我之前在一些实验中看到了行为-XX:+UseSerialGC
和多次System.gc()
调用但不喜欢GC线程的需要.谁知道,随着我们的应用程序和Java的发展,它是否会继续发挥作用.肯定有更好的办法.
什么是迫使我System.gc()
四次打电话(但不是立刻)的逻辑,这些东西记录在哪里?
为了寻找文档-XX:MaxHeapFreeRatio
并且-XX:MinHeapFreeRatio
只使用它-XX:+UseSerialGC
,我阅读了java工具/可执行文件的文档,并且在任何地方都没有提到它-XX:MaxHeapFreeRatio
,-XX:MinHeapFreeRatio
只能使用它-XX:+UseSerialGC
.事实上,修复问题[JDK-8028391]使Min/MaxHeapFreeRatio标志可管理说:
为了使应用程序能够控制允许更多或更少GC的方式和时间,标志-XX:MinHeapFreeRatio和-XX:MaxHeapFreeRatio应该是可管理的.还应在默认并行收集器中实现对这些标志的支持.
一个评论的固定问题,说:
作为自适应大小策略的一部分,ParallelGC还添加了对这些标志的支持.
我已经检查了,修复问题中引用的补丁反向移植到openjdk-8确实包含在我正在使用的openjdk-8版本的源代码包tarball中.所以它显然应该在"默认的并行收集器"中工作,但不像我在这篇文章中所证明的那样.我还没有发现任何文档说它应该只能使用-XX:+UseSerialGC
.正如我在这里记载的那样,即使这是不可靠/冒险的.
我不能只是得到-XX:MaxHeapFreeRatio
和-XX:MinHeapFreeRatio
做他们的诺言,而不必去通过所有这些箍?
小智 7
G1(-XX:+ UseG1GC),并行清除(-XX:+ UseParallelGC)和ParallelOld(-XX:+ UseParallelOldGC)会在堆收缩时返回内存.我不太确定Serial和CMS,他们在我的实验中没有缩小它们的堆.
两个并行收集器确实需要许多GC,然后将堆缩小到"可接受"的大小.这是每个设计.他们故意坚持堆,假设将来需要它.设置标志-XX:GCTimeRatio = 1会稍微改善这种情况,但仍需要几个GC缩小很多.
G1非常适合快速缩小堆,因此对于上面描述的用例,我会说它可以通过使用G1并
System.gc()
在释放所有缓存和类加载器等后运行来解决 .
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6498735
归档时间: |
|
查看次数: |
2856 次 |
最近记录: |