Skip to content
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

增加class的加载缓存,解决频繁加载class会使jvm的方法区空间不足导致OOM的问题 #677

Merged
merged 1 commit into from
Feb 22, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public ReturnT<String> run(TriggerParam triggerParam) {
// valid handler
if (jobHandler == null) {
try {
IJobHandler originJobHandler = GlueFactory.getInstance().loadNewInstance(triggerParam.getGlueSource());
IJobHandler originJobHandler = GlueFactory.getInstance().loadNewInstance(triggerParam.getJobId(), triggerParam.getGlueSource());
jobHandler = new GlueJobHandler(originJobHandler, triggerParam.getGlueUpdatetime());
} catch (Exception e) {
logger.error(e.getMessage(), e);
Expand Down
34 changes: 32 additions & 2 deletions xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import com.xxl.job.core.handler.IJobHandler;
import groovy.lang.GroovyClassLoader;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.concurrent.ConcurrentHashMap;

/**
* glue factory, product class/object by name
*
Expand All @@ -30,6 +34,8 @@ public static void refreshInstance(int type){
*/
private GroovyClassLoader groovyClassLoader = new GroovyClassLoader();

private static final ConcurrentHashMap<String, Class<?>> CLASS_CACHE = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Long, String> JOBID_MD5KEY_CACHE = new ConcurrentHashMap<>();

/**
* load new instance, prototype
Expand All @@ -38,9 +44,9 @@ public static void refreshInstance(int type){
* @return
* @throws Exception
*/
public IJobHandler loadNewInstance(String codeSource) throws Exception{
public IJobHandler loadNewInstance(long jobId, String codeSource) throws Exception{
if (codeSource!=null && codeSource.trim().length()>0) {
Class<?> clazz = groovyClassLoader.parseClass(codeSource);
Class<?> clazz = getCodeSourceClass(jobId, codeSource);
if (clazz != null) {
Object instance = clazz.newInstance();
if (instance!=null) {
Expand All @@ -66,4 +72,28 @@ public void injectService(Object instance) {
// do something
}

private Class<?> getCodeSourceClass(long jobId, String codeSource){
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5 = md.digest(codeSource.getBytes());
BigInteger no = new BigInteger(1, md5);
String md5Str = no.toString(16);
Class<?> clazz = CLASS_CACHE.get(md5Str);
if(clazz == null){
clazz = groovyClassLoader.parseClass(codeSource);
Class<?> preClazz = CLASS_CACHE.putIfAbsent(md5Str, clazz);

// 如果代碼有變化則刪除之前class緩存
if(preClazz == null){
String preMd5 = JOBID_MD5KEY_CACHE.put(jobId, md5Str);
if(preMd5 != null){
CLASS_CACHE.remove(preMd5);
}
}
}
return clazz;
} catch (Exception e) {
return groovyClassLoader.parseClass(codeSource);
}
}
}