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

1.5k Views Asked by At

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

1

There are 1 best solutions below

1
Stephen C On BEST ANSWER

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