起多个tomcat导致内存溢出_邮箱服务(mail)由于Finalizer导致的内存溢出(OOM)...

2543704091b196dcb4e6d43b5b789eea.png

记一次在使用javax.mail-1.5.2.jar包,做邮箱服务。由于Finalizable,导致的内存溢出问题的分析和排查处理过程。

异常现象分析

2f9d59065ec9d53f4c98355e875272dc.png

5c3c7709c3dea22ef859ecb59bc65eb5.png

通过上面的内容可以看到,是应为Finalizer的问题引起的内容泄露,Finalizable对象的生命周期和普通对象的行为是完全不同的,列举如下:

1、JVM创建Finalizable对象

2、JVM创建 java.lang.ref.Finalizer实例,指向刚创建的对象。

3、java.lang.ref.Finalizer类持有新创建的java.lang.ref.Finalizer的实例。这使得下一次新生代GC无法回收这些对象。

4、新生代GC无法清空Eden区,因此会将这些对象移到Survivor区或者老生代。

5、垃圾回收器发现这些对象实现了finalize()方法。因为会把它们添加到java.lang.ref.Finalizer.ReferenceQueue队列中。

6、Finalizer线程会处理这个队列,将里面的对象逐个弹出,并调用它们的finalize()方法。

finalize()方法调用完后,Finalizer线程会将引用从Finalizer类中去掉,因此在下一轮GC中,这些对象就可以被回收了。

7、Finalizer线程会和我们的主线程进行竞争,不过由于它的优先级较低,获取到的CPU时间较少,因此它永远也赶不上主线程的步伐。

程序消耗了所有的可用资源,最后抛出OutOfMemoryError异常。

可通过如下简单的demo进行验证:

package com.onecloud.mail.test;

import java.util.concurrent.atomic.AtomicInteger;

class Finalizable {
    static AtomicInteger aliveCount = new AtomicInteger(0);

    Finalizable() {
 aliveCount.incrementAndGet();
    }

    @Override
    protected void finalize() throws Throwable {
        Finalizable.aliveCount.decrementAndGet();
    }

    public static void main(String args[]) {
        Finalizable f;
        for (int i = 0; ; i++) {
            f = new Finalizable();
            if ((i % 1000000) == 0) {
                System.out.format("After creating %d objects, %d are still alive.%n", new Object[]{i, Finalizable.aliveCount.get()});
            }
        }
    }
}

代码分析

出现问题的类和方法为:AtallMailServiceImpl->receivePOP3Mail,发现其中用到的对象POP3Folder,实现了Object的finalize 方法,

 /**
    * Close the folder when we're finalized.
    */
 protected void finalize() throws Throwable {
         super.finalize();
         close(false);
   }

通过对finalize的原理分析,其出现的问题和此处有关系。

通过深入的查看代码,在POP3Folder存在POP3Message的引用,我们应该在使用POP3Folder对象后,释放对象的占用资源。

解决方案

对应的代码块都在 “AtallMailServiceImpl”类中receivePOP3Mail方法中

1、调用POP3Folder释放资源的方法:

pOP3Folder.close(true);

2、需要调用message的方法,取消缓存

mimeMessage.invalidate(true);

3、先判断邮件是否已收取,然后在读取邮件内容,

使用  String   id = inbox2.getUID(mimeMessage);
替换原来的:String id = pmm.getMessageId();

4、去掉以上预加载的代码,此处会加载很多我们不会用到的信息,占用大量内存。

   FetchProfile profile = new FetchProfile();
   profile.add(FetchProfile.Item.ENVELOPE); // 获取信封
   inbox.fetch(message, profile); // 预获取信息

5、 这里最好做下缓存的处理,避免频繁的查询数据库操作

boolean b = mailDAO.existsById(id);

6、建议调整线程池队列的大小,不要太多的线程同时运行。

以上仅仅是解决了线上环境报内存溢出的问题,关于邮箱服务的双高问题,还有如下的点:

内存和CPU的占用主要体现在如下两点:

  1. 用户附件的下载导致的IO问题。(线程过多时会急速升高),
  2. 邮件内容的过大导致的mysql查询和存储访问问题

后续如果需要对邮箱进行架构调整,需要结合业务分析是否不用收取附件或则采用NIO的方式异步解析附件的文件流。

top - 10:43:51 up 108 days, 17:19,  4 users,  load average: 8.93, 8.96, 7.19
Tasks: 173 total,   3 running, 170 sleeping,   0 stopped,   0 zombie
%Cpu(s): 26.5 us, 67.8 sy,  0.0 ni,  4.6 id,  0.3 wa,  0.0 hi,  0.7 si,  0.1 st
KiB Mem :  7747768 total,   119608 free,  4869892 used,  2758268 buff/cache
KiB Swap:  7340028 total,  5577240 free,  1762788 used.  2523152 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 5944 clouder   20   0 4754948 1.351g   7680 S 378.1 18.3 106:38.69 /usr/java/jdk1.8.0_212-amd64/bin/java -Xms1g -Xmx1g -Xmn512m -jar xiaoHuiMail.jar
 2251 clouder   20   0  135016   2172    928 S   0.3  0.0 216:59.53 ./src/redis-server 127.0.0.1:6380
 2289 clouder   20   0 5626900 201660   6164 S   0.3  2.6 272:20.99 /usr/java/jdk1.8.0_212-amd64/jre/bin/java -Djava.util.logging.config.file=/home/cl+
27161 clouder   20   0 5847724 627228   7280 S   0.3  8.1 126:08.56 /usr/java/jdk1.8.0_212-amd64/jre/bin/java -jar SMART_SPACE_CONTROLLER.jar


procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
10  0 1755072 119712      0 2757704    0    0     0   512 6890 2062 32 67  1  0  0
 9  1 1755068 117648      0 2759916    0    0     0   890 7715 2272 31 67  1  0  0
13  0 1755664 183672      0 2693284    0  600     0 11895 12382 2163 30 69  1  0  0
 8  0 1755664 180064      0 2697052    0    0     0   521 7373 1490 28 71  0  0  0
 4  0 1755656 176912      0 2699956   32    0    32  1088 8625 2345 31 68  1  0  0
 9  0 1755644 173304      0 2703052   32    0    32  1549 10972 4810 32 60  7  1  0
11  1 1755632 164264      0 2711412    0    0  1952 16085 10492 5629 32 54 11  3  0
 3  0 1755624 160508      0 2714640    0    0  1060 16090 6450 3072 29 47 20  4  0
11  0 1755620 159428      0 2716592    0    0    16  9563 14123 5609 35 47 17  1  0
 9  2 1755616 154548      0 2720568    0    0     0  5028 7173 2098 32 67  1  0  0
11  0 1755608 150524      0 2723660   64    0    64  1438 15739 6397 30 59  8  2  0
 8  0 1755604 146396      0 2727640    0    0     0  4399 17011 8086 30 57 11  2  0
 8  0 1755600 143016      0 2731056    0    0     0  3584 8472 2338 30 68  1  0  0
10  0 1755596 141252      0 2732520    0    0     0   534 6632 1935 32 68  0  0  0
 8  0 1755596 137280      0 2736424    0    0     0  2239 7827 2768 30 69  0  0  0
10  0 1755592 134452      0 2739080    0    0     8   411 13234 3465 30 63  6  1  0
10  1 1755592 131344      0 2741968    0    0     0  3906 6330 1168 27 73  0  0  0
10  0 1755592 128776      0 2744492    0    0     0  7301 6829 1976 29 71  0  0  0
 7  1 1755592 125300      0 2748200    0    0     0   783 6578 1994 28 71  0  0  0
 9  1 1755592 121952      0 2751560    0    0     0  2354 7009 2496 30 70  0  0  0
11  0 1755588 126604      0 2754096    0    0     0   880 17984 7569 32 54 13  2  0
10  0 1755584 125748      0 2755360    0    0     8 10881 16753 4258 37 58  3  2  0


avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          25.50    0.00   74.50    0.00    0.00    0.00

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
xvda              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
xvdb              0.00     1.00    0.00  181.00     0.00  5173.00    57.16     0.34    1.88    0.00    1.88   0.24   4.40
dm-0              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          26.25    0.00   73.75    0.00    0.00    0.00

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
xvda              0.00     1.00    0.00    5.00     0.00    36.00    14.40     0.00    0.60    0.00    0.60   0.20   0.10
xvdb              0.00     0.00    0.00  132.00     0.00  3625.50    54.93     0.21    1.60    0.00    1.60   0.23   3.00
dm-0              0.00     0.00    0.00    6.00     0.00    36.00    12.00     0.00    0.67    0.00    0.67   0.17   0.10
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          33.92    0.00   66.08    0.00    0.00    0.00

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
xvda              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
xvdb              0.00     2.00    0.00  800.00     0.00 34402.50    86.01    18.90   23.62    0.00   23.62   0.20  16.30
dm-0              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00

调整后的GC信息

778c8a968fc9ac3efaaa7ab71ae22886.png

伙伴们,如果有遇到内存溢出的相关问题,都可以给我留言,另外关于邮箱服务的优化,如果有想法的小伙伴,也可以给我留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值