Skip to content

Commit a2d6063

Browse files
authored
Change WeakConcurrentMap's cleaner thread's CCL centrally (#804)
1 parent ce4e0ed commit a2d6063

File tree

4 files changed

+54
-13
lines changed

4 files changed

+54
-13
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*-
2+
* #%L
3+
* Elastic APM Java agent
4+
* %%
5+
* Copyright (C) 2018 - 2019 Elastic and contributors
6+
* %%
7+
* Licensed to Elasticsearch B.V. under one or more contributor
8+
* license agreements. See the NOTICE file distributed with
9+
* this work for additional information regarding copyright
10+
* ownership. Elasticsearch B.V. licenses this file to you under
11+
* the Apache License, Version 2.0 (the "License"); you may
12+
* not use this file except in compliance with the License.
13+
* You may obtain a copy of the License at
14+
*
15+
* http://www.apache.org/licenses/LICENSE-2.0
16+
*
17+
* Unless required by applicable law or agreed to in writing,
18+
* software distributed under the License is distributed on an
19+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20+
* KIND, either express or implied. See the License for the
21+
* specific language governing permissions and limitations
22+
* under the License.
23+
* #L%
24+
*/
25+
package co.elastic.apm.agent.util;
26+
27+
import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap;
28+
29+
public class DataStructures {
30+
31+
/**
32+
* Use this utility method for WeakConcurrentMap creation if it is created in the context of a request processing
33+
* thread whose context class loader is the web application ClassLoader.
34+
* This leaks the web application ClassLoader when the application is undeployed/redeployed.
35+
* <p>
36+
* Tomcat will then stop the thread because it thinks it was created by the web application.
37+
* That means that the map will never be cleared, creating a severe memory leak.
38+
*
39+
* @param <K> map key type
40+
* @param <V> map value type
41+
* @return a new WeakConcurrentMap with a cleaner thread who's context class loader is the system/bootstrap class loader
42+
*/
43+
public static <K, V> WeakConcurrentMap<K, V> createWeakConcurrentMapWithCleanerThread() {
44+
WeakConcurrentMap<K, V> map = new WeakConcurrentMap<>(true);
45+
map.getCleanerThread().setContextClassLoader(null);
46+
return map;
47+
}
48+
}

apm-agent-plugins/apm-jdbc-plugin/src/main/java/co/elastic/apm/agent/jdbc/helper/JdbcHelper.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import co.elastic.apm.agent.bci.VisibleForAdvice;
2828
import co.elastic.apm.agent.impl.transaction.Span;
2929
import co.elastic.apm.agent.impl.transaction.TraceContextHolder;
30+
import co.elastic.apm.agent.util.DataStructures;
3031
import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap;
3132

3233
import javax.annotation.Nullable;
@@ -35,17 +36,7 @@
3536
public abstract class JdbcHelper {
3637
@SuppressWarnings("WeakerAccess")
3738
@VisibleForAdvice
38-
public static final WeakConcurrentMap<Object, String> statementSqlMap;
39-
40-
static {
41-
statementSqlMap = new WeakConcurrentMap<>(true);
42-
// This class will probably be loaded in the context of a request processing thread
43-
// whose context class loader is the web application ClassLoader.
44-
// This leaks the web application ClassLoader when the application is undeployed/redeployed.
45-
// Tomcat will then stop the thread because it thinks it was created by the web application.
46-
// That means that the map will never be cleared, creating a severe memory leak.
47-
statementSqlMap.getCleanerThread().setContextClassLoader(null);
48-
}
39+
public static final WeakConcurrentMap<Object, String> statementSqlMap = DataStructures.createWeakConcurrentMapWithCleanerThread();
4940

5041
/**
5142
* Maps the provided sql to the provided Statement object

apm-agent-plugins/apm-jdbc-plugin/src/main/java/co/elastic/apm/agent/jdbc/helper/JdbcHelperImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import co.elastic.apm.agent.impl.transaction.Span;
3030
import co.elastic.apm.agent.impl.transaction.TraceContextHolder;
3131
import co.elastic.apm.agent.jdbc.signature.SignatureParser;
32+
import co.elastic.apm.agent.util.DataStructures;
3233
import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap;
3334
import org.slf4j.Logger;
3435
import org.slf4j.LoggerFactory;
@@ -43,7 +44,7 @@ public class JdbcHelperImpl extends JdbcHelper {
4344
public static final String DB_SPAN_ACTION = "query";
4445

4546
private static final Logger logger = LoggerFactory.getLogger(JdbcHelperImpl.class);
46-
private static final WeakConcurrentMap<Connection, ConnectionMetaData> metaDataMap = new WeakConcurrentMap<Connection, ConnectionMetaData>(true);
47+
private static final WeakConcurrentMap<Connection, ConnectionMetaData> metaDataMap = DataStructures.createWeakConcurrentMapWithCleanerThread();
4748

4849
@VisibleForAdvice
4950
public static final ThreadLocal<SignatureParser> SIGNATURE_PARSER_THREAD_LOCAL = new ThreadLocal<SignatureParser>() {

apm-agent-plugins/apm-urlconnection-plugin/src/main/java/co/elastic/apm/agent/urlconnection/HttpUrlConnectionInstrumentation.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import co.elastic.apm.agent.http.client.HttpClientHelper;
3030
import co.elastic.apm.agent.impl.transaction.Span;
3131
import co.elastic.apm.agent.impl.transaction.TraceContext;
32+
import co.elastic.apm.agent.util.DataStructures;
3233
import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap;
3334
import net.bytebuddy.asm.Advice;
3435
import net.bytebuddy.description.NamedElement;
@@ -51,7 +52,7 @@
5152
public abstract class HttpUrlConnectionInstrumentation extends ElasticApmInstrumentation {
5253

5354
@VisibleForAdvice
54-
public static final WeakConcurrentMap<HttpURLConnection, Span> inFlightSpans = new WeakConcurrentMap<HttpURLConnection, Span>(true);
55+
public static final WeakConcurrentMap<HttpURLConnection, Span> inFlightSpans = DataStructures.createWeakConcurrentMapWithCleanerThread();
5556

5657
@Override
5758
public Collection<String> getInstrumentationGroupNames() {

0 commit comments

Comments
 (0)