Skip to content

Do not specify a JVM garbage collector if none specified in the Coherence yaml #760

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 11, 2025
Merged
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: 2 additions & 2 deletions api/v1/create_statefulset_jvmspec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollector(t *testing.T) {
spec := coh.CoherenceResourceSpec{
JVM: &coh.JVMSpec{
Gc: &coh.JvmGarbageCollectorSpec{
Collector: stringPtr("G1"),
Collector: stringPtr("ZGC"),
},
},
}
Expand All @@ -230,7 +230,7 @@ func TestCreateStatefulSetWithJvmSpecWithGarbageCollector(t *testing.T) {
deployment := createTestDeployment(spec)
// Create expected StatefulSet
stsExpected := createMinimalExpectedStatefulSet(deployment)
addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "G1"})
addEnvVarsToAll(stsExpected, corev1.EnvVar{Name: "JVM_GC_COLLECTOR", Value: "ZGC"})

// assert that the StatefulSet is as expected
assertStatefulSetCreation(t, deployment, stsExpected)
Expand Down
15 changes: 12 additions & 3 deletions docs/jvm/040_gc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,16 @@ If different GC logging arguments are required then the relevant JVM arguments c
The garbage collector to use can be set using the `jvm.gc.collector` field.
This field can be set to either `G1`, `CMS` or `Parallel`
(the field is case-insensitive, invalid values will be silently ignored).
The default collector set, if none has been specified, will be `G1`.

The default collector set, if none has been specified, will be whatever is the default for the JVM being used.

|====
| Parameter | JVM Argument Set
| `G1` | `-XX:+UseG1GC`
| `CMS` | `-XX:+UseConcMarkSweepGC`
| `Parallel` | `-XX:+UseParallelGC`
| `Serial` | `-XX:+UseSerialGC`
| `ZGC` | `-XX:+UseZGC`
|====

For example:
Expand All @@ -80,9 +83,15 @@ metadata:
spec:
jvm:
gc:
collector: "G1"
collector: "ZGC"
----
The example above will add `-XX:+UseG1GC` to the command line.
The example above will add `-XX:+UseZGC` to the command line.

[NOTE]
====
The JVM only allows a single `-XX:Use****` option that sets the garbage collector to use, so the collector should not be
specified in both the `spec.jvm.gc.collector` field, and in the `spec.jvm.args` field.
====

=== Adding Arbitrary GC Args

Expand Down
6 changes: 5 additions & 1 deletion pkg/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,12 +426,16 @@ func configureCommand(details *run_details.RunDetails) error {

gc := strings.ToLower(details.Getenv(v1.EnvVarJvmGcCollector))
switch {
case gc == "" || gc == "g1":
case gc == "g1":
details.AddMemoryOption("-XX:+UseG1GC")
case gc == "cms":
details.AddMemoryOption("-XX:+UseConcMarkSweepGC")
case gc == "parallel":
details.AddMemoryOption("-XX:+UseParallelGC")
case gc == "serial":
details.AddMemoryOption("-XX:+UseSerialGC")
case gc == "zgc":
details.AddMemoryOption("-XX:+UseZGC")
}

maxRAM := details.Getenv(v1.EnvVarJvmMaxRAM)
Expand Down
66 changes: 66 additions & 0 deletions pkg/runner/runner_jvm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,72 @@ func TestJvmGarbageCollectorParallel(t *testing.T) {
g.Expect(e.OsCmd.Args).To(ConsistOf(expected))
}

func TestJvmGarbageCollectorSerial(t *testing.T) {
g := NewGomegaWithT(t)

d := &coh.Coherence{
ObjectMeta: metav1.ObjectMeta{Name: "test"},
Spec: coh.CoherenceStatefulSetResourceSpec{
CoherenceResourceSpec: coh.CoherenceResourceSpec{
JVM: &coh.JVMSpec{
Gc: &coh.JvmGarbageCollectorSpec{
Collector: ptr.To("serial"),
},
},
},
},
}

expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseSerialGC")
verifyConfigFilesWithArgs(t, d, expectedArgs)

args := []string{"server", "--dry-run"}
env := EnvVarsFromDeployment(t, d)

e, err := ExecuteWithArgsAndNewViper(env, args)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(e).NotTo(BeNil())
g.Expect(e.OsCmd).NotTo(BeNil())

g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir))
g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand()))
expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseSerialGC")
g.Expect(e.OsCmd.Args).To(ConsistOf(expected))
}

func TestJvmGarbageCollectorZGC(t *testing.T) {
g := NewGomegaWithT(t)

d := &coh.Coherence{
ObjectMeta: metav1.ObjectMeta{Name: "test"},
Spec: coh.CoherenceStatefulSetResourceSpec{
CoherenceResourceSpec: coh.CoherenceResourceSpec{
JVM: &coh.JVMSpec{
Gc: &coh.JvmGarbageCollectorSpec{
Collector: ptr.To("zgc"),
},
},
},
},
}

expectedArgs := append(GetExpectedArgsFileContentWithoutPrefix("-XX:+UseG1GC"), "-XX:+UseZGC")
verifyConfigFilesWithArgs(t, d, expectedArgs)

args := []string{"server", "--dry-run"}
env := EnvVarsFromDeployment(t, d)

e, err := ExecuteWithArgsAndNewViper(env, args)
g.Expect(err).NotTo(HaveOccurred())
g.Expect(e).NotTo(BeNil())
g.Expect(e.OsCmd).NotTo(BeNil())

g.Expect(e.OsCmd.Dir).To(Equal(TestAppDir))
g.Expect(e.OsCmd.Path).To(Equal(GetJavaCommand()))
expected := append(RemoveArgWithPrefix(GetMinimalExpectedArgs(t), "-XX:+UseG1GC"), "-XX:+UseZGC")
g.Expect(e.OsCmd.Args).To(ConsistOf(expected))
}

func TestJvmGarbageCollectorLoggingTrue(t *testing.T) {
g := NewGomegaWithT(t)

Expand Down
1 change: 0 additions & 1 deletion pkg/runner/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ func AppendCommonExpectedNonServerArgs(args []string, role string) []string {
"-Dcoherence.operator.diagnostics.dir=/coherence-operator/jvm/unknown/unknown",
"-XX:HeapDumpPath=/coherence-operator/jvm/unknown/unknown/heap-dumps/unknown-unknown.hprof",
"-Dcoherence.operator.can.resume.services=true",
"-XX:+UseG1GC",
"-Dcoherence.ttl=0",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:ErrorFile=/coherence-operator/jvm/unknown/unknown/hs-err-unknown-unknown.log",
Expand Down