Home > Back-end >  Why my JVM has so many old char and string?
Why my JVM has so many old char and string?

Time:11-30

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 ...

  1. the JVM may ignore that request entirely,
  2. it might not run a full GC (that's possibly implementation dependent),
  3. 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.

  • Related