iteye_16970
2013-04-09 20:36
浏览 403
已采纳

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]

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • a1000005aa 2013-04-11 09:37
    已采纳

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

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

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

    点赞 打赏 评论
  • runfriends 2013-04-09 22:38

    改成下面的代码
    [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]

    点赞 打赏 评论
  • hejiaqi789 2013-04-10 14:36

    没有太明白你要想做什么.
    提示一点吧:
    每调用一次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);  
    


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

    点赞 打赏 评论

相关推荐 更多相似问题