3

I have machine with 16G RAM. I run a java application with arguments -Xms9G -Xmx9G. When I run top command I see that my java process is taking 13.8g VIRT, but only 4.6g of RES.

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 5019 root      20   0 13.8g 4.7g  18m S  0.7 30.7   3:28.39 java                                     

On running pmap command, I see that only ~3.9g of heap is present as RES, rest 5.7g is in virtual.

Address           Kbytes     RSS   Dirty Mode   Mapping
0000000580000000 9452384 4074228 4074228 rw---    [ anon ]

Upon monitoring HPCUR with jvmtop, I observe that the GC is triggered when the HPCUR reaches about 3g.

PID MAIN-CLASS        HPCUR HPMAX NHCUR NHMAX    CPU     GC    VM USERNAME   #T DL
 5019 .1-SNAPSHOT.jar  408m 9216m  192m   n/a  0.25%  0.00% O8U20   webapp  823

I observe that the RES for the process increases gradually, heap memory in RES (by pmap) also increases gradually too. As a result GC threshold increases.

I have several questions about this behavior.

  1. Is only the heap that is present in RES used, and not the VIRT?
  2. If I have allotted 9G min heap (-Xms), then initially why only 3.9g RES is allotted. Isn't this same as keeping -Xms low? What is the point of keeping -Xms=-Xmx then?
  3. On what basis is it decided that how much heap should be in RES? Read somewhere that its managed by OS, but any rough logic?
  4. Any way to make sure, that the allotted heap is actually used?
FlapPy
  • 160
  • 11
  • [Here](https://serverfault.com/questions/138427/what-does-virtual-memory-size-in-top-mean) is a short explanation of VIRT memory. From that I would say: yes, HEAP is only RES (because it needs real memory, unlike VIRT). That answers 3 as all HEAP is in RES. Can you elaborate on question 4? What do you mean by used? The garbage collector is there to free memory that is not used anymore which does not mean that it will give back the memory to the OS. – cmoetzing May 28 '19 at 05:44
  • "That answers 3 as all HEAP is in RES", my min heap size is 9g still only 4.7g is present as RES and that is the actual heap which is being used. What I meant by 4th was that is there any way to ensure that all 9g heap is present as RES, as it will prevent frequent GC invocations which was reason for increasing heap size. – FlapPy May 28 '19 at 06:38

2 Answers2

3
  • VIRT denotes Virtual memory - this is the entire reserved address space of the process. RSS is the resident set size - the portion of the virtual address space allocated in physical RAM. For any address range (not only the heap) RSS is the subset of VIRT, possibly complete or empty. Seems like you already explored pmap - for each virtual address range it shows the exact amount of physically allocated memory (RSS).
  • OS allocates physical pages lazily on the first access. That's why even committed memory is not the part of RSS until the corresponding pages are read or written to. The fact that the large portion of heap is not in RSS means that this part of the heap has never been touched. See also this question.
  • There is a JVM option -XX:+AlwaysPreTouch that forcibly touches every page of the heap thus making it the part of RSS. Try java -Xms9G -Xmx9G -XX:+AlwaysPreTouch.
apangin
  • 92,924
  • 10
  • 193
  • 247
  • 1
    Re: "The fact that the large portion of heap is not in RSS means that this part of the heap has never been touched" Could that also mean that part of the heap was swapped out on the disk or garbage-collected and returned to the OS? – Juraj Martinka May 30 '19 at 07:23
  • 2
    @JurajMartinka I mean, the committed heap. When GC returns heap memory back to the OS, it explicitly uncommitts the range. The point about swapping is right. But if someone has a large portion of heap swapped out, he or she has a much bigger problem :) – apangin May 30 '19 at 09:48
-1
  1. Yes HEAP is RES (as long as it fits in main memory)
  2. This answer suggests that -Xms is a hint to GC at what point a full garbage collection is necessary. Testing with my local JVM I can confirm that it does not immediately reserve the memory. What you gain is that your JVM does not block a lot of unused memory but will reach you lower bound faster as there are less GC runs.
  3. Answered by 1. : RES always contains all of HEAP
  4. My understanding is that your options will achieve what you intend to. Your application will grab 9GB of memory and then start garbage collection more frequently. There are other options like MinHeapFreeRatio and options that depend on the gargbage collector used if you need more optimization.

Did you print GC logs and verify that something is wrong? If you see a lot of GC runs on application startup before 9G is reached I would look further. If there is hardly any GC run before hitting 9G I would say everything is fine.

cmoetzing
  • 742
  • 3
  • 16
  • Got it, actually I had set young generation size (G1MaxNewSizePercent) too, because of which the heap memory in RES increased quickly initially, till it reached max young generation size, and thereafter it increased gradually as old generation took time to fill up. Thanks a lot. – FlapPy May 28 '19 at 15:38
  • 2
    Heap memory doesn't always have to be counted in RSS. In particular, you can have -Xmx larger than the size of physical memory available on the machine. In that case, part of the heap may be swapped out on the disk which may make some operations (Full GC in particular) painfully slow. This is related to overcommit - see http://www.etalabs.net/overcommit.html – Juraj Martinka May 30 '19 at 07:14
  • 1
    @JurajMartinka I think this comment is extremely good. Take the most used orchestrator tool right now : kubernetes. If does not have support for swap, but almost every docker container that is run by it has `vm.overcommit_memory=1`, a big surprise to all those "certified kubernetes admins" :) – Eugene May 21 '20 at 13:51