mirror of
https://gitee.com/arthas/arthas.git
synced 2024-11-29 18:58:37 +08:00
classloader command support jdk.internal.loader.ClassLoaders$AppClassLoade. #2350
This commit is contained in:
parent
fcfd8eeb62
commit
4fc682265c
@ -15,6 +15,7 @@ import com.taobao.arthas.core.shell.handlers.Handler;
|
||||
import com.taobao.arthas.core.util.ClassUtils;
|
||||
import com.taobao.arthas.core.util.ClassLoaderUtils;
|
||||
import com.taobao.arthas.core.util.ResultUtils;
|
||||
import com.taobao.arthas.core.util.StringUtils;
|
||||
import com.taobao.arthas.core.util.affect.RowAffect;
|
||||
import com.taobao.middleware.cli.annotations.Description;
|
||||
import com.taobao.middleware.cli.annotations.Name;
|
||||
@ -23,7 +24,6 @@ import com.taobao.middleware.cli.annotations.Summary;
|
||||
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.security.CodeSource;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
@ -246,14 +246,14 @@ public class ClassLoaderCommand extends AnnotatedCommand {
|
||||
private void processClassLoader(CommandProcess process, Instrumentation inst, ClassLoader targetClassLoader) {
|
||||
RowAffect affect = new RowAffect();
|
||||
if (targetClassLoader != null) {
|
||||
if (targetClassLoader instanceof URLClassLoader) {
|
||||
List<String> classLoaderUrls = getClassLoaderUrls(targetClassLoader);
|
||||
affect.rCnt(classLoaderUrls.size());
|
||||
if (classLoaderUrls.isEmpty()) {
|
||||
URL[] classLoaderUrls = ClassLoaderUtils.getUrls(targetClassLoader);
|
||||
if (classLoaderUrls != null) {
|
||||
affect.rCnt(classLoaderUrls.length);
|
||||
if (classLoaderUrls.length == 0) {
|
||||
process.appendResult(new MessageModel("urls is empty."));
|
||||
} else {
|
||||
process.appendResult(new ClassLoaderModel().setUrls(classLoaderUrls));
|
||||
affect.rCnt(classLoaderUrls.size());
|
||||
process.appendResult(new ClassLoaderModel().setUrls(StringUtils.toStringList(classLoaderUrls)));
|
||||
affect.rCnt(classLoaderUrls.length);
|
||||
}
|
||||
} else {
|
||||
process.appendResult(new MessageModel("not a URLClassLoader."));
|
||||
@ -403,20 +403,6 @@ public class ClassLoaderCommand extends AnnotatedCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> getClassLoaderUrls(ClassLoader classLoader) {
|
||||
List<String> urlStrs = new ArrayList<String>();
|
||||
if (classLoader instanceof URLClassLoader) {
|
||||
URLClassLoader cl = (URLClassLoader) classLoader;
|
||||
URL[] urls = cl.getURLs();
|
||||
if (urls != null) {
|
||||
for (URL url : urls) {
|
||||
urlStrs.add(url.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return urlStrs;
|
||||
}
|
||||
|
||||
private Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats(Instrumentation inst) {
|
||||
Map<ClassLoaderVO, ClassLoaderUrlStat> urlStats = new HashMap<ClassLoaderVO, ClassLoaderUrlStat>();
|
||||
Map<ClassLoader, Set<String>> usedUrlsMap = new HashMap<ClassLoader, Set<String>>();
|
||||
@ -441,13 +427,17 @@ public class ClassLoaderCommand extends AnnotatedCommand {
|
||||
for (Entry<ClassLoader, Set<String>> entry : usedUrlsMap.entrySet()) {
|
||||
ClassLoader loader = entry.getKey();
|
||||
Set<String> usedUrls = entry.getValue();
|
||||
List<String> allUrls = getClassLoaderUrls(loader);
|
||||
URL[] allUrls = ClassLoaderUtils.getUrls(loader);
|
||||
List<String> unusedUrls = new ArrayList<String>();
|
||||
for (String url : allUrls) {
|
||||
if (!usedUrls.contains(url)) {
|
||||
unusedUrls.add(url);
|
||||
if (allUrls != null) {
|
||||
for (URL url : allUrls) {
|
||||
String urlStr = url.toString();
|
||||
if (!usedUrls.contains(urlStr)) {
|
||||
unusedUrls.add(urlStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
urlStats.put(ClassUtils.createClassLoaderVO(loader), new ClassLoaderUrlStat(usedUrls, unusedUrls));
|
||||
}
|
||||
return urlStats;
|
||||
|
@ -1,6 +1,9 @@
|
||||
package com.taobao.arthas.core.util;
|
||||
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -120,4 +123,56 @@ public class ClassLoaderUtils {
|
||||
}
|
||||
return matchClassLoaders;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "restriction" })
|
||||
public static URL[] getUrls(ClassLoader classLoader) {
|
||||
if (classLoader instanceof URLClassLoader) {
|
||||
return ((URLClassLoader) classLoader).getURLs();
|
||||
}
|
||||
|
||||
// jdk9
|
||||
if (classLoader.getClass().getName().startsWith("jdk.internal.loader.ClassLoaders$")) {
|
||||
try {
|
||||
Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
field.setAccessible(true);
|
||||
sun.misc.Unsafe unsafe = (sun.misc.Unsafe) field.get(null);
|
||||
|
||||
Class<?> ucpOwner = classLoader.getClass();
|
||||
Field ucpField = null;
|
||||
|
||||
// jdk 9~15: jdk.internal.loader.ClassLoaders$AppClassLoader.ucp
|
||||
// jdk 16~17: jdk.internal.loader.BuiltinClassLoader.ucp
|
||||
while (ucpField == null && !ucpOwner.getName().equals("java.lang.Object")) {
|
||||
try {
|
||||
ucpField = ucpOwner.getDeclaredField("ucp");
|
||||
} catch (NoSuchFieldException ex) {
|
||||
ucpOwner = ucpOwner.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (ucpField == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long ucpFieldOffset = unsafe.objectFieldOffset(ucpField);
|
||||
Object ucpObject = unsafe.getObject(classLoader, ucpFieldOffset);
|
||||
if (ucpObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// jdk.internal.loader.URLClassPath.path
|
||||
Field pathField = ucpField.getType().getDeclaredField("path");
|
||||
if (pathField == null) {
|
||||
return null;
|
||||
}
|
||||
long pathFieldOffset = unsafe.objectFieldOffset(pathField);
|
||||
ArrayList<URL> path = (ArrayList<URL>) unsafe.getObject(ucpObject, pathFieldOffset);
|
||||
|
||||
return path.toArray(new URL[path.size()]);
|
||||
} catch (Throwable e) {
|
||||
// ignore
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,11 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
@ -981,4 +983,15 @@ public abstract class StringUtils {
|
||||
public static String beautifyName(String name) {
|
||||
return name.replace(' ', '_').toLowerCase();
|
||||
}
|
||||
|
||||
public static List<String> toStringList(URL[] urls) {
|
||||
if (urls != null) {
|
||||
List<String> result = new ArrayList<String>(urls.length);
|
||||
for (URL url : urls) {
|
||||
result.add(url.toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user