Java的RAM使用率与任务管理器所说的不对应 [英] Java's RAM usage doesn't correspond to what the Task Manager says

查看:159
本文介绍了Java的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使用最少的资源,我该如何解决这个问题?



编辑:



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

解决方案

结论:



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






通常:



您的基本假设是错误的。



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



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



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



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



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



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



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



如果你想要一个GC也试图通过在垃圾收集期间缩小它来使堆大小变小,通过设置 -XX:+ UseG1GC Java标记来尝试 garabage first(G1)GC



示例:



这将打印出所有以字节为单位的值。



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

 系统.out.println(的String.format( 初始化:\t%,d,ManagementFactory.getMemoryMXBean()getHeapMemoryUsage()getInit())。); 
System.out.println(String.format(Max:\ t%,d%n,ManagementFactory.getMemoryMXBean()。getHeapMemoryUsage()。getMax()));

线程outputThread =新线程(() - > {
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(例外e){}
});

线程allocThread = new线程(() - > {
try {
int val = 0;
Thread.sleep(500); //等待1 / 2秒
createArray();
Thread.sleep(500); //等待另外1/2秒
System.gc(); //强制GC,应该清理数组
return;
} catch(例外e){}
});

outputThread.start();
allocThread.start();

createArray()只是以下小方法:

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

- 结果ParallelOldGC

 初始值:262,144,000 
最大值:3,715,629,056

0ms - >使用:6,606,272
0ms - >上传:251,658,240
100ms - >使用:6,606,272
100ms - >上传:251,658,240
200ms - >使用:6,606,272
200ms - >上传:251,658,240
300ms - >使用:6,606,272
300ms - >上传:251,658,240
400ms - >使用:6,606,272
400ms - >委托:251,658,240
500ms - >使用:1,080,348,112
500ms - >上市时间:1,325,924,352
600ms - >使用:1,080,348,112
600ms - >上传:1,325,924,352
700ms - >使用:1,080,348,112
700ms - >上传:1,325,924,352
800ms - >使用:1,080,348,112
800ms - >上传:1,325,924,352
900ms - >使用:1,080,348,112
900ms - >上传:1,325,924,352
1000ms - >使用:1,080,348,112
1000ms - >上传:1,325,924,352
1100ms - >使用:1,080,348,112
1100ms - >上传:1,325,924,352
1200ms - >使用:2,261,768
1200ms - >上传:1,325,924,352
1300ms - >使用:2,261,768
1300ms - >上传:1,325,924,352

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



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



- 结果G1

 初始值:262,144,000 
最大值:4,179,623,936

0ms - >使用:2,097,152
0ms - >上传:262,144,000
100毫秒 - >使用:2,097,152
100毫秒 - >委托:262,144,000
200ms - >使用:2,097,152
200ms - >上传:262,144,000
$ 300 - >二手:2,097,152
300ms - >委托:262,144,000
400ms - >使用:2,097,152
400ms - >委托:262,144,000
500ms - >使用:1,074,364,464
500ms - >上传:1,336,934,400
600ms - >使用:1,074,364,464
600ms - >上传:1,336,934,400
700ms - >使用:1,074,364,464
700ms - >上市时间:1,336,934,400
800ms - >使用:1,074,364,464
800ms - >上传:1,336,934,400
900ms - >二手:1,074,364,464
900ms - >上传:1,336,934,400
1000ms - >使用:492,520
1000ms - >上传:8,388,608
1100ms - >使用:492,520
1100ms - >上传:8,388,608
1200ms - >使用:492,520
1200ms - >委托:8,388,608

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



更多信息:



但请记住, >堆大小仍将与任务管理器中显示的不同。来自


I have been playing with Java's JVM by making a 1024^3 (basically 1Gb) length byte array. I measured the RAM usage before, after the array creation and after the array's destruction by the garbage collector, using both the Task Manager (looking at the process) and this little snippet:

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

The aforementioned code shows 2Mb, 1029Mb and 2Mb, respectively. -> It all seems normal. However, when looking at the TaskManager, the RAM usage by Java is 2mb at first, then goes to 1052Mb and stays there, even if the snippet shows 2Mb.

As I would like to have Java use the least resource, how can I solve this problem?

Edit:

I have done some research and have figured out the terms to use. In fact, the native memory's does not resemble the heap memory's value, and is often greater than the heap memory. Is there a way to reduce the native memory used, so that it is close to the heap memory?

解决方案

Conclusion:

Use the garbage first (G1) GC (default GC in Java 9), this garbage collector also shrinks the heap size (which, in conclusion, will also shrink the overall "native memory" used) on garabage collections, compared to the ParallelOldGC (default GC in Java 7 and Java 8), which seldom to never shrinks the heap size!


Generally:

Your basic assumption is wrong.

You assume you code snippet shows the heap size. This is not correct. It shows the heap utilization. This means "How much space of my heap is used?". Runtime.getRuntime().totalMemory() shows the heap size, Runtime.getRuntime().freeMemory() shows the free heap size, their difference shows the heap utilization (used size).

Your heap starts with an initial size, with 0 bytes utilization because no object is yet created, and a max heap size. Max heap size describes the size to which the garbage collector is allowed to resize the heap (e.g.if there is not enough space for a very large object)

As next step after creating the empty heap, automatically, some objects are loaded (class objects, etc.), they generally should fit easily in the initial heap size.

Then, your code starts running and allocates objects. As soon as there is no more space in your Eden space (the heap is splitted up into the young generation (Eden, survivor-from and survivor-to space) and old generation, look up additional resources if you are interested in these details), a garbage collection is triggered.

During a garbage collection, the garbage collector may decide to resize the heap (as mentioned above when talking about max heap size). This happens in your case, because your initial heap size is too small to fit your 1GB object. Therefore the heap size is increased, somewhere between initial heap size and max heap size.

Then, after your big object died, the next GC could make the heap smaller again, but it does not have to. Why? It's below the max heap size, that's all the GC cares for. Some garbage collection algorithms shrink the heap again, some don't.

Espacially the ParallelOldGC, the default GC in Java 7 and Java 8, does seldom to never shrink the heap.

If you want a GC that also tries to keep heap size small by shrinking it during a garbage collection, try the garabage first (G1) GC by setting the -XX:+UseG1GC Java flag.

Example:

This will print out all values in byte.

You will get an overview, how both GCs work and how many space is used when using either of them.

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() is just the following small method:

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

--Result ParallelOldGC:

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

You can see, my heap starts with an initial size of about 260MB, with an allowed maximum size (size to which the GC may decide to resize you heap) of about 3,7 GB.

Before creating the array, about 6MB of my heap is used. Then the big array gets created, and my heap size (commited size) is increased to 1,3GB, with about 1GB (the array) used. Then I force a garbage collection, that collects the array. Yet, my heap size stays at 1,3GB, because the GC does not care about shrinking it again, just the utilization goes down on 2MB.

--Result G1:

Init:   262,144,000
Max:    4,179,623,936

0ms ->  Used:       2,097,152
0ms ->  Commited:   262,144,000
100ms   ->  Used:       2,097,152
100ms   ->  Commited:   262,144,000
200ms   ->  Used:       2,097,152
200ms   ->  Commited:   262,144,000
300ms   ->  Used:       2,097,152
300ms   ->  Commited:   262,144,000
400ms   ->  Used:       2,097,152
400ms   ->  Commited:   262,144,000
500ms   ->  Used:       1,074,364,464
500ms   ->  Commited:   1,336,934,400
600ms   ->  Used:       1,074,364,464
600ms   ->  Commited:   1,336,934,400
700ms   ->  Used:       1,074,364,464
700ms   ->  Commited:   1,336,934,400
800ms   ->  Used:       1,074,364,464
800ms   ->  Commited:   1,336,934,400
900ms   ->  Used:       1,074,364,464
900ms   ->  Commited:   1,336,934,400
1000ms  ->  Used:       492,520
1000ms  ->  Commited:   8,388,608
1100ms  ->  Used:       492,520
1100ms  ->  Commited:   8,388,608
1200ms  ->  Used:       492,520
1200ms  ->  Commited:   8,388,608

And here we go! The G1 GC cares about small heaps! After the the object is cleaned, not only the utilization goes down to about 0,5MB but also the heap size gets shrinked to 8MB (compared to 1,3GB in ParallelOldGC)

Further info:

But, keep in mind, that the heap size will still differ from what is shown in the task manager. The following image from Wikipedia - Java virtual machine illustrates that the heap is only a part of the full JVM memory:

这篇关于Java的RAM使用率与任务管理器所说的不对应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆