Java 内存泄漏问题

因为系统有内存泄露问题,导致频繁的Full GC,用jmap将内存使用情况dump下来,然后通过mat分析了一下,发现是由于缓存map和更新该map的线程池导致的,截图见附件,下面这个是涉及到的类,研究了好几天这个问题,现在终于定位到具体的代码,耐于经验有限,想请教一下大家都是怎么处理系统中缓存数据的,有闲暇时间的帮看下下面的代码应该如何修改。。

还有个问题就是,定时更新run()里的程序总是不会立即执行,scheduleAtFixedRate的第二个参数设为0也不管用,只有这次执行完,下次再走这儿时cacheMap里才有上次的数据。所以只好在外面再执行一遍,总觉得这么写很奇怪

[code="java"]
public class CachedDataManager extends DataManagerDecorator {

private static ScheduledExecutorService pool;
private long timeLimited;//缓存中数据更新间隔时间 60s
private int poolSize;//线程池大小,20
private static int cacheSize;
public static Map cacheMap;// = new HashMap();

public Object getResult(final String methodName, final Map parameterMap) {

if (cacheMap == null) {
  synchronized (CachedDataManager.class) {
    if (cacheMap == null) {
      cacheMap = new ConcurrentLinkedHashMap.Builder()
             .maximumWeightedCapacity(cacheSize).build();
   }
 }
}

// 根据HashCode生成缓存map的key
final String mapKey = new KeyCreater(methodName, parameterMap)
                   .getHashCode();

// 缓存中没有该条数据则放入有定时更新策略的线程池
if (!cacheMap.containsKey(mapKey)) {

  if (pool == null) {
     pool = Executors.newScheduledThreadPool(poolSize);
  }
  pool.scheduleAtFixedRate(new Runnable() {

    @Override
    public void run() {

      Object obj = dataManager.getResult(methodName, parameterMap);
      cacheMap.put(mapKey, obj);

     }
   }, 0, timeLimited, TimeUnit.SECONDS);
 } else if (cacheMap.get(mapKey) != null) {
   return cacheMap.get(mapKey);
 }
            //因为上面的不会立即执行,所以第一次查询执行这里
  Object obj = dataManager.getResult(methodName, parameterMap);
  cacheMap.put(mapKey, obj);

  return cacheMap.get(mapKey);
  }

}

[/code]

看你的截图,有153个对象在每隔60秒调用一次缓存更新,也就是说有153个Key.

你的线程池只有25个,可能就排到delayQueue上去了,解决方案就是增加线程池的大小,而且你这个线程根据key只会增加不会减少。

所以想要彻底解决问题,需要重新设计缓存的方案.

改成下面的代码
[code="java"]
public class CachedDataManager extends DataManagerDecorator {

private static int cacheSize;
public static Map cacheMap;// = new HashMap();

public Object getResult(final String methodName, final Map parameterMap) {

if (cacheMap == null) {
  synchronized (CachedDataManager.class) {
    if (cacheMap == null) {
      cacheMap = new ConcurrentLinkedHashMap.Builder()
             .maximumWeightedCapacity(cacheSize).build();
   }
 }
}

// 根据HashCode生成缓存map的key
final String mapKey = new KeyCreater(methodName, parameterMap)
                   .getHashCode();

Object obj=cacheMap.get(mapKey);
if (obj!=null) {
      obj = dataManager.getResult(methodName, parameterMap);
      cacheMap.put(mapKey, obj);
 }
 return obj;

}
}
/*
使用线程池更慢,实际上在一个线程内减少了线程切换和创建的开销,性能更好一些。
你说的没有立即执行就是因为线程切换。
实际上线程任务一旦提交就在执行了,只是在线程任务完成put之前母线程就get,所以你在47行得不到。
*/
[/code]

没有太明白你要想做什么.
提示一点吧:
每调用一次getResult这个方法的时候!cacheMap.containsKey(mapKey)都会启一个线程.

pool.scheduleAtFixedRate(new Runnable() {

    @Override  
    public void run() {  

      Object obj = dataManager.getResult(methodName, parameterMap);  
      cacheMap.put(mapKey, obj);  

     }  
   }, 0, timeLimited, TimeUnit.SECONDS);  


线程数量会不断增加。没有释放?