jmap -histo {pid}
shows the following result:
num #instances #bytes class name
----------------------------------------------
1: 4787259 1007093680 [C
2: 6049019 191502048 [B
3: 198580 125701976 [I
4: 5212228 125093472 java.lang.String
While run jmap -histo:live {pid}
shows the following result:
num #instances #bytes class name
----------------------------------------------
1: 463375 140980752 [C
2: 9832 63080312 [I
3: 563438 31161448 [B
4: 461206 11068944 java.lang.String
You can see that there are lots of Char and String are not live but still occupy heap memory. Is this normal or do I need to concern? I hope JVM can clean up some useless String to save memory, as I am pretty sure all these Strings are different and won't be used again and no need to keep in memory for future reuse purpose.
I mainly want to know the difference between jmap -histo: live
and jmap -histo
, there are over 1000M of Char in jmap -histo
but only 140M in jmap -histo:live
, where are the other 860M Chars? and why they are't be GC? When will these Chars be GC? How can I make them immediately GC to save memory?
CodePudding user response:
As @boneill points out, under the hood jmap -histo:live
performs a full GC ... to determine what objects are live. And jmap -histo
... doesn't.
Why my JVM has so many old char and string?
Is this normal or do I need to concern?
It is hard to say. There is insufficient evidence.
But, without other evidence, I'd say "not concerning".
where are the other 860M Chars?
First of all [C
doesn't mean Char
. It means char[]
.
Where are they? Well my reading is that they are unreachable. (Not live). They are candidates for garbage collection.
... and why they aren't be GC?
Because the GC hasn't collected them yet.
Java garbage collection is ... complicated. Many of the collectors are generational meaning that they split the heap into new and old object spaces. The new space is collected frequently. The old space is collected infrequently. So if most of those objects have been tenured to the old space, they may life a relatively long time after they have become unreachable.
That is one possible explanation.
When will these Chars be GC?
When the old space is collected. Probably.
How can I make them immediately GC to save memory?
You could call System.gc()
to ask the JVM to run a (typically) full garbage collection. But ...
- the JVM may ignore that request entirely,
- it might not run a full GC (that's possibly implementation dependent),
- even if the objects are collected, you most likely won't save any actual memory.
Why don't you save memory? Because the JVM hangs on to the free space it got back ... ready to allocate new objects. So the memory is not returned to the OS for other applications to use. (There is some complicated logic for heap resizing, but as a rule the JVM gives back memory reluctantly; i.e. only after a number of full GC cycles.)
Finally, calling System.gc()
in your application code is bad for performance ... in most circumstances. There are other Q&As that explain why.