4

I have a Java program that creates a dozen arrays of of approximately 160 million in length each. The arrays contain primitives (char, short, and floats). In my algorithm, I've noticed (via jprofiler) that the GC runs a fair bit on my system (Windows VM machine on Google Cloud, 16 CPU cores, 64GB RAM) but I can't figure out why the GC is running so often and consuming 80% of total compute CPU power.

So I thought: If I could figure out (either through jvm commands/logs or preferably via a profiler just as jprofiler) what precise objects it was "garbage collecting", I could have a chance to understand what's going on and either fix a simple issue or rearchitect based on my better understanding of what Java is doing. (To the best of my knowledge, I have minimized object creations; I do use a lot of jdk8 parallel streaming features though, so I don't know if that is somehow causing GC issues.) Is there a way to determine which objects (or which object types) the GC is trying to garbage collect at any specific time so that I can better understand why the GC is running so often and so hard?

Jonathan Sylvester
  • 1,275
  • 10
  • 23
  • 1
    Just to understand it correctly: you didn’t realize that there could be a problem, i.e. had no performance problem, until the profiling tool told you that GC is spending 80% of the CPU time? Perhaps, it’s just that your application doesn’t need much CPU time for its own? Besides that, you are bothering too much with irrelevant details. The first thing you should pay attention to, is, “*How much heap memory has been allocated by the JVM?*” and “*How much of the heap space is actually in use by the JVM?*”. – Holger Jul 31 '18 at 11:45
  • I noticed that the CPU wasn't at 100% usage (which is what I would have expected) and then upon profiling I noticed that the GC was running a fair bit. In therms of answer your other 2 questions, I've set the -Xmx to 33G, but I've noticed that the amount of "used size" (according to jprofiler) varied from 11G to 15G and the commited size varied from 16G to 25G. I'm guessing, though, that there's no explicit (or at least "easy") way to determine which objects (or object types) the GC is "collecting" so that I can trace the (potential) problem? – Jonathan Sylvester Aug 01 '18 at 14:34
  • 1
    The problem is, unlike the colloquial term “garbage collector” suggests, the JVM doesn’t collect garbage, but rather traverses the objects which are reachable, hence, still alive. After moving these object into a new memory region, the entire source memory block can be considered free, without knowing what kind a old objects it formerly contained. This implies that a) we cannot identify these dead objects without extra effort and b) we don’t want or need to identify them, as these old objects do not imply any work to the JVM. The still alive objects matter, e.g. when having an almost full heap – Holger Aug 01 '18 at 15:20
  • 1
    But since garbage collection *does* use the CPU, not using 100% CPU suggests that the garbage collection is not a performance factor here at all. Having a not even remotely full heap supports this assumption. Apparently, your application’s performance is dominated by I/O operations (or it has not enough work/threads for all CPUs or suffers from locking). – Holger Aug 01 '18 at 15:25
  • @Holger That's an excellent, excellent point...will investigate.... – Jonathan Sylvester Aug 01 '18 at 18:14

1 Answers1

0

In JProfiler, you can use allocation recording for this purpose.

To show garbage collected objects in the "Recorded objects" view, change the liveness selector in the tool bar to either "Garbage collected objects" or "Live and garbage collected objects". The options dialog of the allocation call tree and allocation hot spot views has an equivalent drop-down.

Ingo Kegel
  • 46,523
  • 10
  • 71
  • 102