java.lang.OutOfMemoryError: unable to create new native thread
阿神
阿神 2017-04-17 17:50:04
0
3
1057

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

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());
        }
    }
}
阿神
阿神

闭关修行中......

全部回覆(3)
Peter_Zhu
  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的大小。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板