Java’s RAM usage does not correspond to what the task manager says

I play the Java JVM by making 1024 ^ 3 (basically 1GB) byte arrays Before using the task manager (viewing the process) and this small fragment, I measured the RAM usage after the array was created and destroyed by the garbage collector:

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

The above codes display 2MB, 1029mb and 2MB respectively. – > All this seems normal However, when looking at the taskmanager, Java's RAM utilization was initially 2MB, then went to 1052mb and remained unchanged, even though the code segment was displayed as 2MB

Since I want java to use the least resources, how can I solve this problem?

Edit:

I did some research and found the terms to use In fact, the value of native memory is not similar to heap memory and is usually larger than heap memory Is there any way to reduce the use of native memory close to heap memory?

Solution

Conclusion:

Using the garbage first (G1) GC (the default GC in Java 9), the garbage collector also reduces the heap size compared with the parallelold GC (finally, it also reduces the overall "native memory" used in the garbage collection) (the default GC in Java 7 and Java 8 rarely never reduces the heap size!

Usually:

Your basic assumption is wrong

You assume that the code snippet shows the heap size This is not true It shows heap utilization This means "how much space does my heap use?" Runtime. getRuntime(). Totalmemory() displays the heap size runtime getRuntime(). Freememory () shows the free heap size, and their difference shows the heap utilization (size used)

Your heap starts with the initial size and uses 0 bytes because no objects have been created and the maximum heap size The maximum heap size description allows the garbage collector to resize the heap size (for example, if there is not enough space for very large objects)

In the next step after creating an empty heap, automatically load some objects (class objects, etc.), which should usually easily fit the initial heap size

Then your code starts running and allocating objects As long as there is no more space in your eden space (the heap is divided into the younger generation (Eden, survivors and survivors - space) and the older generation. If you are interested in these details, please find other resources), trigger garbage collection

During garbage collection, the garbage collector may decide to resize the heap (as mentioned above, when discussing the maximum heap size) This happens in your case because your initial heap size is too small for your 1GB object Therefore, the heap size increases, between the initial heap size and the maximum heap size

Then, after your big object dies, the next GC can make the heap smaller again, but it's not necessary Why? It is below the maximum heap size, which is the concern of GC Some garbage collection algorithms shrink the heap again, while others do not

In particular, parallelold GC, the default GC in Java 7 and Java 8, rarely and never shrink the heap

If you want the GC to try to keep the heap size small by reducing the heap during garbage collection, try using garbage (G1) GC first by setting the - XX: useg1gc Java flag

Example:

This will print out all values in bytes

You will get an overview of how both GCS work and the space used when using either

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%,i,ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()));
            System.out.println(String.format("%dms\t->\tCommited:\t%,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 a 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,272
100ms   ->  Commited:   251,240
200ms   ->  Used:       6,272
200ms   ->  Commited:   251,240
300ms   ->  Used:       6,272
300ms   ->  Commited:   251,240
400ms   ->  Used:       6,272
400ms   ->  Commited:   251,240
500ms   ->  Used:       1,080,348,112
500ms   ->  Commited:   1,325,924,352
600ms   ->  Used:       1,112
600ms   ->  Commited:   1,352
700ms   ->  Used:       1,112
700ms   ->  Commited:   1,352
800ms   ->  Used:       1,112
800ms   ->  Commited:   1,352
900ms   ->  Used:       1,112
900ms   ->  Commited:   1,352
1000ms  ->  Used:       1,112
1000ms  ->  Commited:   1,352
1100ms  ->  Used:       1,112
1100ms  ->  Commited:   1,352
1200ms  ->  Used:       2,261,768
1200ms  ->  Commited:   1,352
1300ms  ->  Used:       2,768
1300ms  ->  Commited:   1,352

As you can see, the initial size of my heap is about 260MB, and the maximum size allowed (the GC may decide to resize) is about 3.7 GB

About 6MB of heap was used before the array was created Then create a large array, increase my heap size (commit size) to 1,3gb, and use about 1GB (array) Then I force the garbage collection of the collection array However, my heap size remained at 1 because GC didn't care about shrinking again, but the utilization decreased to 2MB

– result G1:

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

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

Now let's start! G1 GC cares about the small pile! After cleaning up objects, not only the utilization is reduced to about 0.5Mb, but also the heap size is reduced to 8MB (compared with 1,3gb in paralleloldgc)

More information:

However, remember that the heap size will still be different from that shown in the task manager The following image from Wikipedia – Java virtual machine shows that the heap is only part of the complete JVM memory:

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>