Live data from Hacker News

Epsilon: The JDK’s Do-Nothing Garbage Collector

blogs.oracle.com

31–40 of 77 posts

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#31
post #17

See also Raymond Chen: https://devblogs.microsoft.com/oldnewthing/20180228-00/?p=98... - who quotes the story of a piece of embedded software which accepted leaking since it would be used in the runtime of a missile.

Sounds like the maintenance shut downs that window OS would need from time to time.

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#32
post #17

See also Raymond Chen: https://devblogs.microsoft.com/oldnewthing/20180228-00/?p=98... - who quotes the story of a piece of embedded software which accepted leaking since it would be used in the runtime of a missile.

Similarly, the cooling solution for some missiles' control-systems' is simply 'thermal inertia', i.e. they just race against overheating, as program-termination can be relied upon to occur first.

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#33
post #25

Earlier quoted context omitted.

I think the concern is those resources might be external and not cleaning up correctly leaves them in an inconsistent state. Not saying this is best practice but I've seen it done.

Finalisers are not guaranteed to be called by GC in theory, and in practice they run asynchronously even if they are going to be called, so aren't likely to be called if you GC and then exit. So how does calling GC help with anything?

I agree with you and how it's not reliable. I just remember the Rust community going through this same kerfuffle with their Drop trait not being guaranteed not too long ago.

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#34

Earlier quoted context omitted.

Hence my question.

I still don't understand your question, sorry: > can't the regular GCs just not clean up on program exit Why do you need to clean up your memory - at all, GC or otherwise - on program exit? The process and all its resources will be gone.

But regular GCs DO run at the end of the program, so my question was, why don't they just skip the final cleanup.

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#35

Now I'm no Java expert, far from it, so would appreciate any answers to this. I'm interacting with bunch of CLIs that are either in Java or using the JVM otherwise (Clojure mostly), how much of the startup time for this things can be attributed to the GC? It's mentioned in the article that short-running programs (almost all CLIs I use) could use Epsilon since the heap is cleared on exit anyways. But wondering how muc…

One interesting thing for you may be Class-Data Sharing feature that keeps already parsed class data across restarts and can re-use it with other JVM instances running same code. It also allows JVM to share these data in memory with other JVMs running on same host so in some use cases it can both speed up startup time and save memory.

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#36

Now I'm no Java expert, far from it, so would appreciate any answers to this. I'm interacting with bunch of CLIs that are either in Java or using the JVM otherwise (Clojure mostly), how much of the startup time for this things can be attributed to the GC? It's mentioned in the article that short-running programs (almost all CLIs I use) could use Epsilon since the heap is cleared on exit anyways. But wondering how muc…

I think the overhead of GC is negligible for many small programs. Claes Redestad @ Oracle gives a good overview here. https://cl4es.github.io/2019/11/20/OpenJDK-Startup-Update.ht... I would look into GraalVM native images if you want fast startup.

There's some precedent for chopping out the GC for short-lived applications. DMD, the (self-hosting) D compiler, does this, effectively using a push-only stack for the heap, never doing anything akin to freeing memory. [0]

In modern GCs, allocation is already as fast as can be (pointer-bump allocation), so I imagine the only win in chopping out the GC is that you don't need to initialize the GC (it's otherwise roughly equivalent to simply terminating before the GC needs to be invoked).

Perhaps the DMD example isn't quite the same, though, as it's possible its GC has slower allocation than pointer-bump.

[0] https://www.drdobbs.com/cpp/increasing-compiler-speed-by-ove...

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#37

Earlier quoted context omitted.

I still don't understand your question, sorry: > can't the regular GCs just not clean up on program exit Why do you need to clean up your memory - at all, GC or otherwise - on program exit? The process and all its resources will be gone.

But regular GCs DO run at the end of the program, so my question was, why don't they just skip the final cleanup.

> But regular GCs DO run at the end of the program

Which GCs do that? I'm not aware of any.

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#38

Earlier quoted context omitted.

I still don't understand your question, sorry: > can't the regular GCs just not clean up on program exit Why do you need to clean up your memory - at all, GC or otherwise - on program exit? The process and all its resources will be gone.

But regular GCs DO run at the end of the program, so my question was, why don't they just skip the final cleanup.

Unless I'm missing something, the only reason you'd run a GC cycle on termination is to invoke finalizers.

If the platform doesn't feature finalizers, or if it is known that they've not been used, there'd be no point at all.

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#39

To address the short-running program issue, can't the regular GCs just not clean up on program exit?

The post misleads readers into thinking that JVM runs the GC before exit. It does not.

When I was writing the Epsilon JEP, I meant that it might be futile to have a hundreds-of-ms-long GC cycle, when the program exits very soon anyway, and the heap would be abandoned wholesale. The important bit of trivia is that GC might be invoked long before 'the whole memory' is exhausted. There are several reasons to do this: learning the application profile to size up generations or collection triggers, minimizing the startup footprint, etc. GC cycle then can be seen as the upfront cost that pays off in future. With the extremely short-lived job that future never comes.

Contrived example:

  $ cat AL.java
  import java.util.*;

  public class AL {
       public static void main(String... args) throws Throwable {
          List l = new ArrayList();
          for (int c = 0; c 
Ooof, 12.5 seconds to run, and about 2 cpu-minutes taken with Parallel:

  $ time jdk11.0.5/bin/java -XX:+UnlockExperimentalVMOptions -Xms3g -Xmx3g -XX:+UseParallelGC -Xlog:gc AL
  [0.015s][info][gc] Using Parallel
  [0.988s][info][gc] GC(0) Pause Young (Allocation Failure) 768M->469M(2944M) 550.699ms
  ...
  [12.281s][info][gc] GC(3) Pause Full (Ergonomics) 1795M->1615M(2944M) 7660.045ms
  100000000

  real 0m12.464s 
  user 1m53.618s
  sys 0m1.087s
Much better with G1, but we still took 11 cycles that accrued enough pauses to affect the end-to-end timing. Plus GC threads took some of our precious CPU.

  $ time jdk11.0.5/bin/java -XX:+UnlockExperimentalVMOptions -Xms3g -Xmx3g -XX:+UseG1GC -Xlog:gc AL
  [0.031s][info][gc] Using G1
  [0.452s][info][gc] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 316M->314M(3072M) 124.119ms
  ...
  [2.518s][info][gc] GC(11) Pause Young (Normal) (G1 Evacuation Pause) 2321M->2324M(3072M) 79.496ms
  100000000

  real 0m2.953s 
  user 0m16.880s
  sys 0m0.872s
Now Epsilon, whoosh, 1.5s end-to-end, and less than 1s of user time, which is probably the only running Java thread itself, plus some OS memory management on allocation path.

  $ time jdk11.0.5/bin/java -XX:+UnlockExperimentalVMOptions -Xms3g -Xmx3g -XX:+UseEpsilonGC -Xlog:gc AL
  [0.004s][info][gc] Using Epsilon
  ...
  [1.387s][info][gc] Heap: 3072M reserved, 3072M (100.00%) committed, 2731M (88.93%) used

  real 0m1.480s
  user 0m0.830s
  sys 0m0.699s
You might think fully concurrent GCs would solve this, and they partially do, by avoiding large pauses. But they still eat CPUs. For example, while Shenandoah is close to Epsilon in doing the whole thing in about 1.7s wall clock time, it still takes quite significant CPU time. Therefore, that benefit is there because machine has spare CPUs to offload that work to.

  $ time jdk11-shenandoah/bin/java -XX:+UnlockExperimentalVMOptions -Xms3g -Xmx3g -XX:+UseShenandoahGC -Xlog:gc AL
  [0.009s][info][gc] Using Shenandoah
  ...
  [0.913s][info][gc] Trigger: Learning 3 of 5. Free (1651M) is below initial threshold (2150M)
  [0.913s][info][gc] GC(2) Concurrent reset 1265M->1267M(3072M) 0.689ms
  [0.914s][info][gc] GC(2) Pause Init Mark 0.111ms
  [1.276s][info][gc] GC(2) Concurrent marking 1267M->1925M(3072M) 361.985ms
  [1.306s][info][gc] GC(2) Pause Final Mark 0.465ms
  [1.306s][info][gc] GC(2) Concurrent cleanup 1924M->1748M(3072M) 0.171ms

  real 0m1.761s 
  user 0m5.688s 
  sys 0m0.633s

Re: Epsilon: The JDK’s Do-Nothing Garbage Collector

#40
post #33

Earlier quoted context omitted.

Finalisers are not guaranteed to be called by GC in theory, and in practice they run asynchronously even if they are going to be called, so aren't likely to be called if you GC and then exit. So how does calling GC help with anything?

I agree with you and how it's not reliable. I just remember the Rust community going through this same kerfuffle with their Drop trait not being guaranteed not too long ago.

That was four and a half years ago; time flies!
Post reply on HN