1

Could someone explain me (best would be to lead to documentation) what is the difference between the two:

jcmd ${jpid} GC.run_finalization
jcmd ${jpid} GC.run

As in the application (springboot + tomcat) after a test (using gatling) much memory stays allocated and not freed. "Saw" graph shows that GC is feeing something but not everything In the application life cycle:

  • attack starts (gatling simulation), extra tomcat executor threads are started, attack ends
  • after some time spring/tomcat session objects timeout (session.servlet.timeout)
  • I would expect session objects to be released and extra tomcat executors to be released but it does NOT happen
  • I waited a long time (let say days)... this is where the graph above starts
  • If I execute GC.run_finalization - nothing happens (just faster "saw drop")
  • If I execute GC.run - memory is released as shown on the image

The only documentation I found is https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#gc-- , but it confused me even more (I understood that GC.run_finalization would suggest finalization of objects for release while GC.run would suggest memory objects to be prepared for future reuse and not necessary freed).

Thanks in advance

Maciej Wakuła
  • 125
  • 1
  • 9
  • 1
    Did you take a look at this article https://javaconceptoftheday.com/garbage-collection-finalize-method-java/? – Giancarlo Romeo May 13 '20 at 13:41
  • It took me a moment to read it and digest the content but I still do not understand what is happening. GC.run_finalization would call the finalizers but then why memory is not sweept by GC in next "saw drop" and only when I call implicite GC.run ? – Maciej Wakuła May 13 '20 at 13:53
  • 2
    Is there any reason to assume that running finalizers has any relevance at all? What happens if you just perform `run`, without `run_finalization`? – Holger May 13 '20 at 14:10

1 Answers1

3

(best would be to lead to documentation)

There is documentation for jcmd and its subcommands here:

That documentation explains that jcmd <pid or class> help will list the available commands, and jcmd <pid or class> help <command> will give you the help information for <command>.


What is the difference between GC.run and GC.run_finalization?

From what I can make out from a brief look at the JVM source code:

  • GC.run runs a full garbage collection. I don't know if finalizers are run (immediately), but I suspect not.

  • GC.run_finalization just calls System.runFinalization(). According to the javadoc, this runs finalizers on objects that are pending finalization; i.e. Java objects that the GC has already found:

    1. to be currently unreachable,
    2. to have a non-default finalize() method, and
    3. to not have already been marked as finalized.

(I understood that GC.run_finalization would suggest finalization of objects for release while GC.run would suggest memory objects to be prepared for future reuse and not necessary freed).

It is not like that. A normal GC cycle is something like this:

  • The garbage collection finds all unreachable objects.
  • Any unreachable objects that need to be finalized are added to the queue.
  • Other unreachable objects are deleted immediately.
  • The GC finishes
  • The finalization thread wakes up and starts processing objects on its queue.
    • Each queued object's finalize method is called and it is marked as having been finalized.

The finalized object are left where they are. They will be deleted by the GC in a future collection provided that they are still unreachable.

Note that finalization is an old mechanism for tidying up objects before they are deleted. The vast majority of Java objects are never finalized.


So this is the explanation for the behavior that you are seeing.

  • The shallow sawtooths are minor collections. They are only collecting the Eden space. Presumably the "attack" is leading to a lot of objects being tenured to the Old space.
  • Calling GC_run triggers a full collection which collects all spaces. That causes a lot more memory to be freed.
  • Calling GC_run_finalization has no effect because finalization doesn't free objects. And probably there are no finalizable objects on the queue anyway.
  • -
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thanks a lot. This is exactly what is happening and mem in tenured/old space is filled.. Along with this (already simplified) scenario I'm observing memory leaks when JVM is running at the edge of its constraints (requests throughput, CPU and memory for the heap). Near the heap limits GC would just run more often but not necessary free the heap (leading to OOM). If some threads encounter memory allocation error then some objects are never cleared (some threads were just killed without finishing their job). MANY THANKS!!! – Maciej Wakuła May 14 '20 at 06:10