现象,tomcat的内存持续飙升,超过-Xmx的限制大小很多,
服务器报警,某tomcat定义的-Xmx是10G,但实际占用了26G内存,超的太TM多了。
想到的可能:jvm本身需要内存,线程需要额外内存,native本地库内存,-Xmx其实只是定义了堆内存,不包括前面这几个。
(1)用 jmap -dump:format=b,file=/data/query5.bin 进程pid 做了dump文件,文件只有7G
(2)用mat分析,看到实际占用内存,只有310多M, 看HistogramFenix,其中 java.lang.ref.Finalizer 占用276MB java.util.zip.Inflater 占用255MB
(3) 搜索,
Java的Finalizer引发的内存溢出 http://www.cnblogs.com/benwu/articles/5812903.html
可知,大量的Finalizer可能引起内存溢出,源头是谁?
(4) java.util.zip.Inflater是gzip解压的一个类,搜索得知
它会调用本地native类,会分配C的堆内存,
必须调用它的end方法,否则C的堆内存不释放,会持续增长。
看工程代码,关于zip的,有此方法:
public static String unCompressStr(byte[] bytes) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(bytes.length); ByteArrayInputStream in = new ByteArrayInputStream(bytes); GZIPInputStream gunzip = new GZIPInputStream(in); byte[] buffer = new byte[bytes.length]; int n; while ((n = gunzip.read(buffer)) >= 0) { out.write(buffer, 0, n); } return out.toString("UTF-8"); }
看看,输入流没有关闭,加上gunzip.close(),它会逐层的关闭流,也就关闭了底层的Inflater。
问题解决。
|