Skip to content

Commit

Permalink
引入ModuleJarLifeCycleProvider接口解决模块泄漏问题
Browse files Browse the repository at this point in the history
  • Loading branch information
dongchenxu committed Jan 4, 2019
1 parent 86e6e33 commit c64dde4
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.alibaba.jvm.sandbox.api.spi;

/**
* 模块Jar包生命周期管理
*
* @author oldmanpushcart@gmail.com
* @since {@code sandbox-api:1.2.0}
*/
public interface ModuleJarLifeCycleProvider {

/**
* 模块Jar文件卸载完所有模块后,正式卸载Jar文件之前之后调用!
*/
void onJarUnLoadCompleted();

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.alibaba.jvm.sandbox.core.classloader;

import com.alibaba.jvm.sandbox.api.annotation.Stealth;
import com.alibaba.jvm.sandbox.api.spi.ModuleJarLifeCycleProvider;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -17,9 +18,11 @@
import java.security.ProtectionDomain;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.jar.JarFile;

import static com.alibaba.jvm.sandbox.api.util.GaStringUtils.getJavaClassName;
import static com.alibaba.jvm.sandbox.core.util.SandboxReflectUtils.*;

/**
Expand Down Expand Up @@ -104,9 +107,21 @@ private void cleanProtectionDomainWhichCameFromModuleClassLoader() {

}

private void onJarUnLoadCompleted() {
try {
final ServiceLoader<ModuleJarLifeCycleProvider> moduleJarLifeCycleProviders
= ServiceLoader.load(ModuleJarLifeCycleProvider.class, this);
for (ModuleJarLifeCycleProvider provider : moduleJarLifeCycleProviders) {
logger.info("unloading module-jar: onJarUnLoadCompleted() loader={};provider={};", this, getJavaClassName(provider.getClass()));
provider.onJarUnLoadCompleted();
}
} catch (Throwable cause) {
logger.warn("unloading module-jar: onJarUnLoadCompleted() occur error! loader={};", this, cause);
}
}

public void closeIfPossible() {

onJarUnLoadCompleted();
try {

// 如果是JDK7+的版本, URLClassLoader实现了Closeable接口,直接调用即可
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void frozen(int listenerId) {
processor.listener
);

processor.clean();
// processor.clean();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,10 @@ int popInvokeId() {
stack.deep(),
listenerId
);
// 这里注释掉,避免频繁删除和创建ThreadLocal的开销
// 采用frozen的方式来释放
// if (stack.isEmpty()) {
// processRef.remove();
// logger.debug("clean TLS: event-processor, listener={};", listenerId);
// }
if (stack.isEmpty()) {
processRef.remove();
logger.debug("clean TLS: event-processor, listener={};", listenerId);
}
return invokeId;
}

Expand Down Expand Up @@ -127,11 +125,6 @@ protected Process initialValue() {
: listener;
}

void clean() {
processRef.remove();
logger.debug("clean TLS: event-processor, listener={};", listenerId);
}


/**
* 校验器,用于校验事件处理器状态是否正确
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.alibaba.jvm.sandbox.api.Information;
import com.alibaba.jvm.sandbox.api.Module;
import com.alibaba.jvm.sandbox.api.spi.ModuleJarLifeCycleProvider;
import com.alibaba.jvm.sandbox.core.classloader.ModuleClassLoader;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -112,6 +113,9 @@ void load(final ModuleJarLoadCallback mjCb,
final ClassLoader preTCL = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(moduleClassLoader);

// 模块Jar加载前回调


try {

final ServiceLoader<Module> moduleServiceLoader = ServiceLoader.load(Module.class, moduleClassLoader);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.alibaba.jvm.sandbox.module.debug;

import ch.qos.logback.classic.LoggerContext;
import com.alibaba.jvm.sandbox.api.spi.ModuleJarLifeCycleProvider;
import org.kohsuke.MetaInfServices;
import org.slf4j.LoggerFactory;

@MetaInfServices(ModuleJarLifeCycleProvider.class)
public class OnJarUnLoadCompleted implements ModuleJarLifeCycleProvider {

@Override
public void onJarUnLoadCompleted() {
closeLogback();
}

// 关闭Logback日志框架
private void closeLogback() {
try {
((LoggerContext) LoggerFactory.getILoggerFactory()).stop();
} catch (Throwable cause) {
cause.printStackTrace();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,20 @@ private ClassLoader getSandboxClassLoader(final Class<?> classOfAgentLauncher)
}

// 清理命名空间所对应的SandboxClassLoader
private ClassLoader cleanSandboxClassLoader(final Class<?> classOfAgentLauncher)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
private ClassLoader cleanSandboxClassLoader(final Class<?> classOfAgentLauncher) {
// 清理AgentLauncher.sandboxClassLoaderMap
final ClassLoader sandboxClassLoader = (ClassLoader) MethodUtils.invokeStaticMethod(
classOfAgentLauncher,
"cleanClassLoader",
configInfo.getNamespace()
);
logger.info("clean SandboxClassLoader from jvm-sandbox[{}] success, for shutdown.", configInfo.getNamespace());
return sandboxClassLoader;
try {
final ClassLoader sandboxClassLoader = (ClassLoader) MethodUtils.invokeStaticMethod(
classOfAgentLauncher,
"cleanClassLoader",
configInfo.getNamespace()
);
logger.info("clean SandboxClassLoader from jvm-sandbox[{}] success, for shutdown.", configInfo.getNamespace());
return sandboxClassLoader;
} catch (Throwable cause) {
logger.warn("clean SandboxClassLoader from jvm-sandbox[{}] occur error for shutdown!", configInfo.getNamespace(), cause);
return null;
}
}

// 清理Spy中对Method的引用
Expand Down Expand Up @@ -83,29 +87,36 @@ private void unloadModules() throws ModuleException {
}

// 卸载自己
private void unloadSelf() throws ModuleException {
private void unloadSelf() {
// 卸载自己
final String self = getClass().getAnnotation(Information.class).id();
moduleManager.unload(self);
logger.info("unload module={} from jvm-sandbox[{}] success, for shutdown.", self, configInfo.getNamespace());
try {
final String self = getClass().getAnnotation(Information.class).id();
moduleManager.unload(self);
} catch (Throwable cause) {
cause.printStackTrace();
}
// logger.info("unload module={} from jvm-sandbox[{}] success, for shutdown.", self, configInfo.getNamespace());
}

// 关闭HTTP服务器
private void shutdownServer(final ClassLoader sandboxClassLoader)
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
private void shutdownServer(final ClassLoader sandboxClassLoader) {

if (null == sandboxClassLoader) {
logger.warn("detection an warning, target SandboxClassLoader[namespace={}] is null, shutdown server will be ignore",
configInfo.getNamespace());
return;
}
try {
if (null == sandboxClassLoader) {
logger.warn("detection an warning, target SandboxClassLoader[namespace={}] is null, shutdown server will be ignore",
configInfo.getNamespace());
return;
}

final Class<?> classOfCoreServer = sandboxClassLoader
.loadClass("com.alibaba.jvm.sandbox.core.server.ProxyCoreServer");
final Object objectOfJettyCoreServer = classOfCoreServer.getMethod("getInstance").invoke(null);
final Method methodOfDestroy = classOfCoreServer.getMethod("destroy");
methodOfDestroy.invoke(objectOfJettyCoreServer);
logger.info("shutdown jvm-sandbox[{}] server success for shutdown.", configInfo.getNamespace());
final Class<?> classOfCoreServer = sandboxClassLoader
.loadClass("com.alibaba.jvm.sandbox.core.server.ProxyCoreServer");
final Object objectOfJettyCoreServer = classOfCoreServer.getMethod("getInstance").invoke(null);
final Method methodOfDestroy = classOfCoreServer.getMethod("destroy");
methodOfDestroy.invoke(objectOfJettyCoreServer);
logger.info("shutdown jvm-sandbox[{}] server success for shutdown.", configInfo.getNamespace());
} catch (Throwable cause) {
logger.warn("shutdown jvm-sandbox[{}] server occur error for shutdown!", configInfo.getNamespace(), cause);
}
}

// @Http("/shutdown")
Expand All @@ -128,11 +139,9 @@ public void shutdown(final PrintWriter writer) throws Exception {
@Override
public void run() {
try {

shutdownServer(getSandboxClassLoader(classOfAgentLauncher));
unloadSelf();
cleanSandboxClassLoader(classOfAgentLauncher);

unloadSelf();
} catch (Throwable cause) {
logger.warn("shutdown jvm-sandbox[{}] failed.", configInfo.getNamespace(), cause);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.alibaba.jvm.sandbox.module.mgr;

import ch.qos.logback.classic.LoggerContext;
import com.alibaba.jvm.sandbox.api.spi.ModuleJarLifeCycleProvider;
import org.kohsuke.MetaInfServices;
import org.slf4j.LoggerFactory;

@MetaInfServices(ModuleJarLifeCycleProvider.class)
public class OnJarUnLoadCompleted implements ModuleJarLifeCycleProvider {

@Override
public void onJarUnLoadCompleted() {
closeLogback();
}

// 关闭Logback日志框架
private void closeLogback() {
try {
((LoggerContext) LoggerFactory.getILoggerFactory()).stop();
} catch (Throwable cause) {
cause.printStackTrace();
}
}

}

0 comments on commit c64dde4

Please sign in to comment.