OutOfMemory 怎么办

Created at 2016-04-05 Updated at 2017-09-01

背景:

线上系统内存泄露挂掉.

分析步骤:

由于内存泄露没有响应,已经无法强制导出内存,那么只能从日志和机器的监控图入手。
从监控的机器数据图中可以看到,在内存泄露时,机器 CPU 已经跑高至 700+% 。
top

  1. 日志方面,使用

    1
    cat worker.log | grep "exception" > error.txt
  2. 发现为 SwitchDispatchManager 线程抛出的无数的异常

    1
    2
    3
    java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
    at java.util.HashMap$KeyIterator.next(HashMap.java:828)
  3. 查看代码发现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    private static Set<String> hasMsgSwitchIp = new HashSet<String>;
    public void addMsg(String ip){
    ...
    hasMsgSwitchIp.add(ip);
    }
    public void run() {
    while (true) {
    try {
    if (!hasMsgSwitchIp.isEmpty()){
    Iterator<String> ite = hasMsgSwitchIp.iterator();
    while(ite.hasNext()){
    String ip = ite.next();
    Queue<SwitchMessage> userObjs = msgMap.get(ip);
    if (userObjs.isEmpty()) {
    synchronized(userObjs){
    if (userObjs.isEmpty()){
    ite.remove();
    continue;
    }
    }
    }
    ...
    }else{
    sleep(500);
    }
    }catch (Exception e) {
    log.error(e.getMessage(), e);
    }
    }
    }
  4. HashSet 并非线程安全,而addMsg()和 run()是不同线程操作,于是导致抛出异常,线程一直未能休眠,于是导致CPU异常跑高,系统跑挂

解决办法

HashSet 改为 Sets.newConcurrentHashSet();

Site by luohuaruxue using Hexo & Random

Hide