Skip to content

Commit fda1ee1

Browse files
authored
Add timeout to awaitGc (#10081)
1 parent 586eea7 commit fda1ee1

File tree

9 files changed

+49
-29
lines changed

9 files changed

+49
-29
lines changed

instrumentation/internal/internal-class-loader/javaagent-integration-tests/src/test/groovy/ResourceInjectionTest.groovy

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
77
import org.apache.commons.lang3.SystemUtils
88

99
import java.lang.ref.WeakReference
10+
import java.time.Duration
1011
import java.util.concurrent.atomic.AtomicReference
1112

1213
import static io.opentelemetry.instrumentation.test.utils.GcUtils.awaitGc
@@ -44,7 +45,7 @@ class ResourceInjectionTest extends AgentInstrumentationSpecification {
4445
def ref = new WeakReference(emptyLoader.get())
4546
emptyLoader.set(null)
4647

47-
awaitGc(ref)
48+
awaitGc(ref, Duration.ofSeconds(10))
4849

4950
then: "HelperInjector doesn't prevent it from being collected"
5051
null == ref.get()

instrumentation/micrometer/micrometer-1.5/testing/src/main/java/io/opentelemetry/instrumentation/micrometer/v1_5/AbstractGaugeTest.java

+5-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.opentelemetry.instrumentation.micrometer.v1_5;
77

88
import static io.opentelemetry.instrumentation.micrometer.v1_5.AbstractCounterTest.INSTRUMENTATION_NAME;
9+
import static io.opentelemetry.instrumentation.test.utils.GcUtils.awaitGc;
910
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
1011
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
1112

@@ -15,6 +16,8 @@
1516
import java.lang.ref.WeakReference;
1617
import java.net.URL;
1718
import java.net.URLClassLoader;
19+
import java.time.Duration;
20+
import java.util.concurrent.TimeoutException;
1821
import java.util.concurrent.atomic.AtomicLong;
1922
import org.assertj.core.api.AbstractIterableAssert;
2023
import org.junit.jupiter.api.Test;
@@ -153,7 +156,7 @@ void gaugesWithSameNameAndDifferentTags() {
153156
}
154157

155158
@Test
156-
void testWeakRefGauge() throws InterruptedException {
159+
void testWeakRefGauge() throws InterruptedException, TimeoutException {
157160
// given
158161
AtomicLong num = new AtomicLong(42);
159162
Gauge.builder("testWeakRefGauge", num, AtomicLong::get)
@@ -175,22 +178,12 @@ void testWeakRefGauge() throws InterruptedException {
175178
// when
176179
WeakReference<AtomicLong> numWeakRef = new WeakReference<>(num);
177180
num = null;
178-
awaitGc(numWeakRef);
181+
awaitGc(numWeakRef, Duration.ofSeconds(10));
179182
testing().clearData();
180183

181184
// then
182185
testing()
183186
.waitAndAssertMetrics(
184187
INSTRUMENTATION_NAME, "testWeakRefGauge", AbstractIterableAssert::isEmpty);
185188
}
186-
187-
private static void awaitGc(WeakReference<?> ref) throws InterruptedException {
188-
while (ref.get() != null) {
189-
if (Thread.interrupted()) {
190-
throw new InterruptedException();
191-
}
192-
System.gc();
193-
System.runFinalization();
194-
}
195-
}
196189
}

javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/test/HelperInjectionTest.groovy

+4-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import net.bytebuddy.dynamic.loading.ClassInjector
1717
import spock.lang.Specification
1818

1919
import java.lang.ref.WeakReference
20+
import java.time.Duration
2021
import java.util.concurrent.atomic.AtomicReference
2122

2223
import static io.opentelemetry.instrumentation.test.utils.ClasspathUtils.isClassLoaded
@@ -53,7 +54,7 @@ class HelperInjectionTest extends Specification {
5354
def ref = new WeakReference(emptyLoader.get())
5455
emptyLoader.set(null)
5556

56-
awaitGc(ref)
57+
awaitGc(ref, Duration.ofSeconds(10))
5758

5859
then: "HelperInjector doesn't prevent it from being collected"
5960
null == ref.get()
@@ -100,7 +101,7 @@ class HelperInjectionTest extends Specification {
100101
def injectorRef = new WeakReference(injector.get())
101102
injector.set(null)
102103

103-
awaitGc(injectorRef)
104+
awaitGc(injectorRef, Duration.ofSeconds(10))
104105

105106
then:
106107
null == injectorRef.get()
@@ -109,7 +110,7 @@ class HelperInjectionTest extends Specification {
109110
def loaderRef = new WeakReference(emptyLoader.get())
110111
emptyLoader.set(null)
111112

112-
awaitGc(loaderRef)
113+
awaitGc(loaderRef, Duration.ofSeconds(10))
113114

114115
then:
115116
null == loaderRef.get()

javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/util/ClassLoaderValueTest.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import io.opentelemetry.instrumentation.test.utils.GcUtils;
1111
import java.lang.ref.WeakReference;
12+
import java.time.Duration;
13+
import java.util.concurrent.TimeoutException;
1214
import org.junit.jupiter.api.Test;
1315

1416
class ClassLoaderValueTest {
@@ -26,7 +28,7 @@ void testClassLoader(ClassLoader classLoader) {
2628
}
2729

2830
@Test
29-
void testGc() throws InterruptedException {
31+
void testGc() throws InterruptedException, TimeoutException {
3032
ClassLoader testClassLoader = new ClassLoader() {};
3133
ClassLoaderValue<Value> classLoaderValue = new ClassLoaderValue<>();
3234
Value value = new Value();
@@ -40,8 +42,8 @@ void testGc() throws InterruptedException {
4042
value = null;
4143
testClassLoader = null;
4244

43-
GcUtils.awaitGc(classLoaderWeakReference);
44-
GcUtils.awaitGc(valueWeakReference);
45+
GcUtils.awaitGc(classLoaderWeakReference, Duration.ofSeconds(10));
46+
GcUtils.awaitGc(valueWeakReference, Duration.ofSeconds(10));
4547

4648
assertThat(classLoaderWeakReference.get()).isNull();
4749
assertThat(valueWeakReference.get()).isNull();

javaagent/src/test/groovy/io/opentelemetry/javaagent/classloading/ClassLoadingTest.groovy

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import io.opentelemetry.javaagent.util.GcUtils
1111
import spock.lang.Specification
1212

1313
import java.lang.ref.WeakReference
14+
import java.time.Duration
1415

1516
import static io.opentelemetry.javaagent.IntegrationTestUtils.createJarWithClasses
1617

@@ -43,7 +44,7 @@ class ClassLoadingTest extends Specification {
4344
loader.loadClass(ClassToInstrument.getName())
4445
loader = null
4546

46-
GcUtils.awaitGc(ref)
47+
GcUtils.awaitGc(ref, Duration.ofSeconds(10))
4748

4849
then:
4950
null == ref.get()

javaagent/src/test/java/io/opentelemetry/javaagent/util/GcUtils.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,25 @@
66
package io.opentelemetry.javaagent.util;
77

88
import java.lang.ref.WeakReference;
9+
import java.time.Duration;
10+
import java.time.temporal.ChronoUnit;
11+
import java.util.concurrent.TimeoutException;
912

1013
public final class GcUtils {
11-
public static void awaitGc(WeakReference<?> ref) throws InterruptedException {
12-
while (ref.get() != null) {
14+
public static void awaitGc(WeakReference<?> ref, Duration timeout)
15+
throws InterruptedException, TimeoutException {
16+
long start = System.currentTimeMillis();
17+
while (ref.get() != null
18+
&& !timeout.minus(System.currentTimeMillis() - start, ChronoUnit.MILLIS).isNegative()) {
1319
if (Thread.interrupted()) {
1420
throw new InterruptedException();
1521
}
1622
System.gc();
1723
System.runFinalization();
1824
}
25+
if (ref.get() != null) {
26+
throw new TimeoutException("reference was not cleared in time");
27+
}
1928
}
2029

2130
private GcUtils() {}

muzzle/src/test/java/io/opentelemetry/javaagent/tooling/muzzle/MuzzleWeakReferenceTestUtil.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@
99
import java.lang.ref.WeakReference;
1010
import java.net.URL;
1111
import java.net.URLClassLoader;
12+
import java.time.Duration;
1213
import java.util.Collections;
14+
import java.util.concurrent.TimeoutException;
1315
import muzzle.TestClasses.MethodBodyAdvice;
1416

1517
public class MuzzleWeakReferenceTestUtil {
1618

1719
// Spock holds strong references to all local variables. For weak reference testing we must create
1820
// our strong references away from Spock in this java class.
1921
// Even returning a WeakReference<ClassLoader> is enough for spock to create a strong ref.
20-
public static boolean classLoaderRefIsGarbageCollected() throws InterruptedException {
22+
public static boolean classLoaderRefIsGarbageCollected()
23+
throws InterruptedException, TimeoutException {
2124
ClassLoader loader = new URLClassLoader(new URL[0], null);
2225
WeakReference<ClassLoader> clRef = new WeakReference<>(loader);
2326
ReferenceCollector collector = new ReferenceCollector(className -> false);
@@ -27,7 +30,7 @@ public static boolean classLoaderRefIsGarbageCollected() throws InterruptedExcep
2730
Collections.emptyList(), collector.getReferences(), className -> false);
2831
refMatcher.getMismatchedReferenceSources(loader);
2932
loader = null;
30-
GcUtils.awaitGc(clRef);
33+
GcUtils.awaitGc(clRef, Duration.ofSeconds(10));
3134
return clRef.get() == null;
3235
}
3336

testing-common/integration-tests/src/test/groovy/context/FieldBackedImplementationTest.groovy

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import java.lang.ref.WeakReference
2222
import java.lang.reflect.Field
2323
import java.lang.reflect.Method
2424
import java.lang.reflect.Modifier
25+
import java.time.Duration
2526
import java.util.concurrent.atomic.AtomicReference
2627

2728
// this test is run using
@@ -182,7 +183,7 @@ class FieldBackedImplementationTest extends AgentInstrumentationSpecification {
182183
int count = keyValue.get().incrementContextCount()
183184
WeakReference<KeyClass> instanceRef = new WeakReference(keyValue.get())
184185
keyValue.set(null)
185-
GcUtils.awaitGc(instanceRef)
186+
GcUtils.awaitGc(instanceRef, Duration.ofSeconds(10))
186187

187188
then:
188189
instanceRef.get() == null

testing-common/src/main/java/io/opentelemetry/instrumentation/test/utils/GcUtils.java

+13-4
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,33 @@
66
package io.opentelemetry.instrumentation.test.utils;
77

88
import java.lang.ref.WeakReference;
9+
import java.time.Duration;
10+
import java.time.temporal.ChronoUnit;
11+
import java.util.concurrent.TimeoutException;
912

1013
public final class GcUtils {
1114

12-
public static void awaitGc() throws InterruptedException {
15+
public static void awaitGc(Duration timeout) throws InterruptedException, TimeoutException {
1316
Object obj = new Object();
1417
WeakReference<Object> ref = new WeakReference<>(obj);
1518
obj = null;
16-
awaitGc(ref);
19+
awaitGc(ref, timeout);
1720
}
1821

19-
public static void awaitGc(WeakReference<?> ref) throws InterruptedException {
20-
while (ref.get() != null) {
22+
public static void awaitGc(WeakReference<?> ref, Duration timeout)
23+
throws InterruptedException, TimeoutException {
24+
long start = System.currentTimeMillis();
25+
while (ref.get() != null
26+
&& !timeout.minus(System.currentTimeMillis() - start, ChronoUnit.MILLIS).isNegative()) {
2127
if (Thread.interrupted()) {
2228
throw new InterruptedException();
2329
}
2430
System.gc();
2531
System.runFinalization();
2632
}
33+
if (ref.get() != null) {
34+
throw new TimeoutException("reference was not cleared in time");
35+
}
2736
}
2837

2938
private GcUtils() {}

0 commit comments

Comments
 (0)