开发者社区> 问答> 正文

java.lang.OutOfMemoryError: 报错

java.lang.OutOfMemoryError: unable to create new native thread

"

程序总是在两三天就报一次内存泄漏的异常,不知道是什么原因引起的,因为项目中有一个地方冲到队列,在队列中创建了很多的线程不知道是不是这个引起了。。。

public class GlobalVariables { public static ExecutorService pool = Executors.newFixedThreadPool(1000); public static BlockingQueue<Object> queue = new ArrayBlockingQueue<Object>(1000); public static Map<Integer, Integer> map = new HashMap<Integer, Integer>();

}

public class AddQueues implements Runnable{ private Object obj;

public AddQueues(Object obj) {
    this.obj = obj;
}
@Override
public void run() {
    try {
        System.out.println("-------------"+obj);
        GlobalVariables.queue.put(obj);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

@Override public Map<String, Object> updateQueuePool(Map<String, Object> map) throws Exception { EntranceVisitCountDTO dto = new EntranceVisitCountDTO(); dto.setAdminUserId(Integer.parseInt(map.get("adminUserId").toString())); GlobalVariables.pool.submit(new AddQueues(dto));

    Map<String,Object> param = new HashMap<String,Object>();
    param.put("result", "yes");
    
    return param;
}

/** * 定时将队列里的数据放到map中 */ @Scheduled(cron = "0/3 * * * * ?") public synchronized void updateVisitCountOfMap(){ try{ if(!GlobalVariables.queue.isEmpty()){
for(int i = 0; i < 100; i++){ Object obj = GlobalVariables.queue.take(); if(obj instanceof EntranceVisitCountDTO){ EntranceVisitCountDTO dto = (EntranceVisitCountDTO)obj; Integer visitCount = GlobalVariables.map.get(dto.getAdminUserId()); if(visitCount != null && GlobalVariables.map.size() <= 1000){ GlobalVariables.map.put(dto.getAdminUserId(), visitCount +1); }else if(GlobalVariables.map.size() > 1000){ visitDayCountService.updateEntranceShowCount(); }else{ GlobalVariables.map.put(dto.getAdminUserId(), 1); } } if(GlobalVariables.queue.isEmpty()){ break; } } } } catch (Exception e) { e.printStackTrace(); } }

/** * 定时将map中的缓存数据同步入口 */ @Scheduled(cron = "0 0/10 * * * ?") public synchronized void updateEntranceShowCount(){ try{ visitDayCountService.updateEntranceShowCount(); } catch (Exception e) { e.printStackTrace(); } }

@Transactional(rollbackFor = Exception.class) @Override public synchronized void updateEntranceShowCount() throws Exception {

if(!GlobalVariables.map.isEmpty()){
    for(Map.Entry<Integer, Integer> entry : GlobalVariables.map.entrySet()){
            
        String day = TimeUtils.getSpecifyDate(0, "yyyy-MM-dd");
        VisitDayCount visitDayCount = (VisitDayCount)visitDayCountDao.getEntranceCountByEntranceInfoIdWithCreateDate(entry.getKey(), day, "VisitDayCount");
        if(null == visitDayCount){
            visitDayCount = new VisitDayCount();
            visitDayCount.setNum(1);
            visitDayCount.setAdminUserId(entry.getKey());
            visitDayCount.setVisitTime(day);
            visitDayCountDao.save(visitDayCount);
        }else{
            visitDayCountDao.updateEntranceVistCount(entry.getKey(), entry.getValue());
        }
            
        GlobalVariables.map.remove(entry.getKey());
    }
}

}

"

展开
收起
因为相信,所以看见。 2020-05-27 10:04:18 2930 0
1 条回答
写回答
取消 提交回答
  • 阿里,我所有的向往

    "

    1. 这段代码的入口应该是updateQueuePool方法,这个方法会生成DTO,然后创建新的job来吧DTO放到queue里面去,而这个queue的消费者是在updateVisitCountOfMap,这个方法每3秒钟消费100个DTO,如果调用updateQueuePooll方法的频率大于消费的频率的话,OOM是早晚的事情

    2. GlobalVariables.map也是类似的问题,每3秒放入最多100个对象,但是每10分钟消费。

    3. GlobalVariables的几个字段都是公开的,意味着任何代码都可以直接使用,这个也是个可能导致问题的因素。

    4. 如果内存有泄露,调用System.gc没任何帮助。

    这段代码问题挺多的,不过不是完整代码,所以也不能确定哪个地方会有内存泄露,你最好让代码运行一段时间,然后用jmap dump下jvm,然后用virtual vm来查看该dump文件,看看到底是queue引用的对象还是map里面的对象没有被回收导致的。

    ######

    'unable to create new native thread'
    很少有这种OOM,一定是代码那里不断的new Thread()造成的。
    改成线程池吧。

    ######

    你设置的线程池大小是1000个,没必要建这么多吧,可以先看下主机是几核几线程,建议调低一点。另外jvm中的xxs分配多大,这个是影响你在jvm中能开多少线程的。在核查xmx的大小。

    "
    2020-05-27 17:06:42
    赞同 展开评论 打赏
问答标签:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud Alibaba - 重新定义 Java Cloud-Native 立即下载
The Reactive Cloud Native Arch 立即下载
JAVA开发手册1.5.0 立即下载