Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/org/javademos/init/Java15.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.javademos.java15.jep372.NashornRemovalDemo;
import org.javademos.java15.jep373.DatagramSocketDemo15;
import org.javademos.java15.jep375.InstanceofPatternMatchingSecondPreview;
import org.javademos.java15.jep379.ShenandoahJEP379;
import org.javademos.java15.jep381.SolarisSparcRemovalDemo;
import org.javademos.java15.jep383.ForeignMemoryAccessDemo;
import org.javademos.java15.jep384.RecordsSecondPreviewDemo;
Expand All @@ -34,12 +35,15 @@ public static ArrayList<IDemo> getDemos() {
java15DemoPool.add(new DatagramSocketDemo15());
// JEP 375
java15DemoPool.add(new InstanceofPatternMatchingSecondPreview());
// JEP 379: Shenandoah: A Low-Pause-Time Garbage Collector (Production)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only place the JEP number here, as for the other demos

java15DemoPool.add(new ShenandoahJEP379());
// JEP 381
java15DemoPool.add(new SolarisSparcRemovalDemo());
// JEP 383
java15DemoPool.add(new ForeignMemoryAccessDemo());
// JEP 384
java15DemoPool.add(new RecordsSecondPreviewDemo());


return java15DemoPool;
}
Expand Down
89 changes: 89 additions & 0 deletions src/main/java/org/javademos/java15/jep379/ShenandoahJEP379.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.javademos.java15.jep379;

import org.javademos.commons.IDemo;
import java.util.ArrayList;
import java.util.List;

/**
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here use the Markdown syntax comments, not old JavaDoc, as in all other demo implementations.

Check for the IDemo.java interface, there are instructions how it should look like.

* ## ☕ JEP 379: Shenandoah: A Low-Pause-Time Garbage Collector (Production)
*
* This JEP finalized the Shenandoah garbage collector, making it a production feature
* in JDK 15. This meant the `-XX:+UnlockExperimentalVMOptions` flag was no longer
* required to use it.
*
* Shenandoah is a **latency-focused** GC that performs most of its work, including
* heap compaction, concurrently with the application threads.
*
* ### Key Benefits:
* - **Low Pause Times:** GC pause times are consistently very short (often < 10ms).
* - **Heap Size Independence:** Pause times are largely independent of the heap size.
* This makes it ideal for applications with very large heaps (hundreds of GBs).
*
* ### History:
* - **JEP 189 (JDK 12):** Shenandoah was first introduced as an *Experimental* feature.
* - **JEP 379 (JDK 15):** Promoted Shenandoah to a *Production* feature.
*
* ### How to Run the Demo:
* Since this feature is configured via JVM arguments, the demo primarily demonstrates
* how to force some GC activity and prints the required flags.
*
* To run the main application with Shenandoah, you only need:
* `java -XX:+UseShenandoahGC -Xms... -Xmx... -jar your-app.jar`
*
* @see <a href="https://openjdk.org/jeps/379">JEP 379</a>
* @see <a href="https://openjdk.org/jeps/189">JEP 189 (Initial Introduction)</a>
*/
public class ShenandoahJEP379 implements IDemo {

private static final int ALLOC_SIZE = 100_000_000; // Allocate 100MB per step
private static final int GC_CYCLES = 5; // Number of cycles to run

@Override
public void demo() {
info(379);

System.out.println("Shenandoah GC is primarily configured with JVM flags, not code.");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, do not use println statements for explanation. Only use it, if it shows something directly related to the executed code. Turn extra information like this (rows 45-50) to classic comments inside the source code.

System.out.println("--------------------------------------------------------------------------------------------------");
System.out.println("To use this collector (on a Java 15+ compatible JDK):");
System.out.println("JVM Flags: -XX:+UseShenandoahGC -Xms4G -Xmx4G -Xlog:gc*=info:file=tmp/shenandoah_gc.log");
System.out.println(" - NOTE: -Xms and -Xmx are recommended to be the same size.");
System.out.println("--------------------------------------------------------------------------------------------------");

try {
System.out.println("Simulating a memory-stressing workload to trigger GC activity...");

// Allocate objects to force GC cycles
List<byte[]> allocationList = new ArrayList<>();
for (int i = 0; i < GC_CYCLES; i++) {
System.out.printf("Cycle %d: Allocating %d bytes (%.2fMB)...%n",
i + 1, ALLOC_SIZE, ALLOC_SIZE / 1024.0 / 1024.0);

// Keep some objects alive (e.g., in a list)
allocationList.add(new byte[ALLOC_SIZE]);

// Allow some time for concurrent GC to run
Thread.sleep(100);
}

System.out.println("\nWorkload finished. Note: Shenandoah attempts to run concurrently.");
System.out.println("The short pauses are only visible when running with GC logging enabled.");
System.out.printf("Final allocated size kept alive: %.2fMB%n",
allocationList.size() * ALLOC_SIZE / 1024.0 / 1024.0);

// Important: Call System.gc() to try and trigger a full GC.
// The logs will show if Shenandoah runs a concurrent cycle or a Stop-The-World (STW) full GC.
System.out.println("\nCalling System.gc()... (Shenandoah typically runs a concurrent cycle)");
System.gc();

// Clear the list to allow all memory to be reclaimed
allocationList.clear();
System.out.println("Cleared allocation list.");

} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (OutOfMemoryError e) {
System.err.println("!!! ERROR: Demo ran out of memory. Try increasing -Xmx size in your VM options. !!!");
}

}
}
8 changes: 8 additions & 0 deletions src/main/resources/JDK15Info.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@
"link": true,
"code": false
},
{
"jep": 379,
"jdk": 15,
"name": "JEP 379 - Shenandoah: A Low-Pause-Time Garbage Collector",
"dscr": "Promoted Shenandoah from an experimental to a production feature.",
"link": false,
"code": true
},
{
"jep": 381,
"jdk": 15,
Expand Down