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: