Java的RAM使用率与任务管理器所说的

时间:2016-02-21 17:18:27

标签: java memory jvm ram

我通过制作1024^3(基本上是1Gb)长度的字节数组来玩Java的JVM。我在使用任务管理器(查看进程)和这个小片段之前,在数组创建之后和数组被垃圾收集器销毁之后测量了RAM使用情况:

public static void showMemory() {
    System.out.println("Memory used: "
            + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024.D * 1024.D) + "mB.");
}

上述代码分别显示2Mb,1029Mb和2Mb。 - >这一切似乎都很正常。 但是,在查看TaskManager时,Java的RAM使用率最初为2mb,然后达到1052Mb并保持不变,即使该代码段显示为2Mb。

由于我希望Java使用最少的资源,我该如何解决这个问题?

修改

我做了一些研究并找出了要使用的术语。实际上,原生内存与内存的值不相似,并且通常大于堆内存。有没有办法减少使用的本机内存,使其接近堆内存?

3 个答案:

答案 0 :(得分:10)

<强>结论:

使用垃圾优先(G1)GC (Java 9中的默认GC),这个垃圾收集器还缩小了堆大小(总之,它也会缩小与 ParallelOldGC (Java 7和Java 8中的默认GC)相比,garabage集合中的整体&#34;本机内存&#34;已经使用了),它很少永远不会缩小堆大小

<强>一般

你的基本假设是错误的。

您假设代码段显示堆大小。这是不正确的。它显示堆利用率。这意味着&#34;我的堆使用了多少空间?&#34;。 Runtime.getRuntime().totalMemory()显示堆大小Runtime.getRuntime().freeMemory()显示可用堆大小,它们的差异显示堆利用率(已用大小)

您的堆以初始大小开头,0字节利用率,因为尚未创建任何对象,以及最大堆大小最大堆大小描述允许垃圾收集器调整堆大小的大小(例如,如果没有足够的空间容纳非常大的对象)

作为创建空堆后的下一步,自动加载一些对象(类对象等),它们通常应该很容易适合初始堆大小。

然后,您的代码开始运行并分配对象。只要您的伊甸园空间没有更多空间(堆被分成年轻一代(伊甸园,幸存者和幸存者 - 太空)和老一代,如果您对这些细节感兴趣,请查找其他资源) ,触发垃圾收集。

在垃圾收集期间,垃圾收集器可能决定调整堆的大小(如上所述,当谈到最大堆大小时)。在您的情况下会发生这种情况,因为初始堆大小太小而不适合您的1GB对象。因此,堆大小会增加,介于初始堆大小最大堆大小之间。

然后,在您的大对象死亡后,下一个GC 可以再次使堆变小,但不必。为什么?它低于最大堆大小,这是GC关注的所有内容。一些垃圾收集算法会再次缩小堆,有些则不会。

特别是 ParallelOldGC ,Java 7和Java 8中的默认GC,很少永远不会缩小堆。

如果您希望GC在垃圾收集过程中通过收缩来尝试保持堆大小小,请通过设置{尝试 garabage first(G1)GC {1}} Java标志。

示例:

这将以字节打印出所有值。

您将获得概述,两个GC如何工作以及使用其中任何一个时使用的空间。

-XX:+UseG1GC

System.out.println(String.format("Init:\t%,d",ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getInit())); System.out.println(String.format("Max:\t%,d%n", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax())); Thread outputThread = new Thread(() -> { try { int i = 0; for(;;) { System.out.println(String.format("%dms\t->\tUsed:\t\t%,d", i, ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed())); System.out.println(String.format("%dms\t->\tCommited:\t%,d", i, ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getCommitted())); Thread.sleep(100); i += 100; } } catch (Exception e) { } }); Thread allocThread = new Thread(() -> { try { int val = 0; Thread.sleep(500); // Wait 1/2 second createArray(); Thread.sleep(500); // Wait another 1/2 seconds System.gc(); // Force a GC, array should be cleaned return; } catch (Exception e) { } }); outputThread.start(); allocThread.start(); 只是以下小方法:

createArray()

- 结果ParallelOldGC

private static void createArray() {
    byte[] arr = new byte[1024 * 1024 * 1024];
}

你可以看到,我的堆的初始大小约为260MB,允许的最大大小(GC可能决定调整大小的大小)大约为3.7 GB。

在创建阵列之前,使用了大约6MB的堆。然后创建大数组,并且我的堆大小(提交的大小)增加到1,3GB,使用大约1GB(数组)。然后我强制收集数组的垃圾收集。然而,我的堆大小保持在1,3GB,因为GC不关心再次缩小它,只是利用率下降到2MB。

- 结果G1

Init:   262,144,000
Max:    3,715,629,056

0ms ->  Used:       6,606,272
0ms ->  Commited:   251,658,240
100ms   ->  Used:       6,606,272
100ms   ->  Commited:   251,658,240
200ms   ->  Used:       6,606,272
200ms   ->  Commited:   251,658,240
300ms   ->  Used:       6,606,272
300ms   ->  Commited:   251,658,240
400ms   ->  Used:       6,606,272
400ms   ->  Commited:   251,658,240
500ms   ->  Used:       1,080,348,112
500ms   ->  Commited:   1,325,924,352
600ms   ->  Used:       1,080,348,112
600ms   ->  Commited:   1,325,924,352
700ms   ->  Used:       1,080,348,112
700ms   ->  Commited:   1,325,924,352
800ms   ->  Used:       1,080,348,112
800ms   ->  Commited:   1,325,924,352
900ms   ->  Used:       1,080,348,112
900ms   ->  Commited:   1,325,924,352
1000ms  ->  Used:       1,080,348,112
1000ms  ->  Commited:   1,325,924,352
1100ms  ->  Used:       1,080,348,112
1100ms  ->  Commited:   1,325,924,352
1200ms  ->  Used:       2,261,768
1200ms  ->  Commited:   1,325,924,352
1300ms  ->  Used:       2,261,768
1300ms  ->  Commited:   1,325,924,352

我们走了! G1 GC关心小堆!清理对象后,不仅利用率降低到大约0.5MB,而且堆大小也缩小到8MB(与ParallelOldGC中的1,3GB相比)

更多信息:

但是,请记住,堆大小仍将与任务管理器中显示的不同。来自following imageWikipedia - Java virtual machine说明堆只是完整JVM内存的一部分:

JVM memory

答案 1 :(得分:2)

堆只是JVM内存中的一个区域。对于诸如共享库,代码,线程堆栈,直接内存和GUI组件之类的东西,JVM在最大堆大小之上额外增加200 - 400 MB并不罕见。

因此,当在该时刻可能正在使用2 MB(MB =兆字节,Mb =兆位)对象时,应用程序可以保留更多。

  

有没有办法减少使用的本机内存,使其接近堆内存?

您可以使用较旧版本的Java,它往往使用较少的内存,较小的最大堆和perm gen,使用较少的额外资源。

答案 2 :(得分:1)

如果对GC使用G1收集器,则可以减小堆大小,但本机内存大小不会减少。在某些应用程序中,分配的本机内存可能超过实际堆。本机堆受到Thrashing的影响。