Java虽然有垃圾回收机制,但是也可能会因为对象被无意引用,导致没有释放,占用了太多内存。常见的有全局集合类
堆对象统计信息
命令:jmap -histo:live pid
描述:显示堆中对象的统计信息
可以看到各个类的实例数和占用内存大小
num #instances #bytes class name
----------------------------------------------
1: 699830 601799480 [C
2: 51782 30054360 [B
3: 1159920 27838080 java.util.LinkedList$Node
4: 1097805 26347320 org.apache.shardingsphere.core.parse.sql.segment.dml.expr.simple.ParameterMarkerExpressionSegment
5: 698311 16759464 java.lang.String
6: 121169 11906736 [Ljava.lang.Object;
7: 94967 8357096 java.lang.reflect.Method
8: 143004 6864192 com.google.common.collect.HashBiMap$BiEntry
9: 202799 6489568 java.util.concurrent.ConcurrentHashMap$Node
10: 196201 6278432 java.util.HashMap$Node
11: 40409 5332520 [Ljava.util.HashMap$Node;
class name的含义
Element Type | Encoding |
---|---|
boolean | Z |
byte | B |
char | C |
class or interface | Lclassname; |
double | D |
float | F |
int | I |
long | J |
short | S |
如果有[
则表示数组,[[
则是二维数组
一般情况下从类的实例数,还是很难定位到内存泄露点,因为没有引用链路,不知道是哪个变量造成了内存泄露
生成内存镜像
命令:jmap -dump:format=b,file=heapdump.hprof [pid]
描述:生成堆转储快照dump文件
dump内存镜像,我们就可以使用内存分析工具(MAT),查看各个类的引用链路,找到内存泄漏点
使用MAT分析
一般使用
Dominator Tree
,因为一般对象的内存占用大小只是该对象本身的大小,不包含其引用其他对象的大小,Dominator Tree可以计算对象以及被其引用的其他对象的大小,这样就可以找到最终导致内存泄露的点
从MAT分析结果来看: ch.qos.logback.classic.LoggerContext
父类ContextBase
中的private StatusManager sm = new BasicStatusManager()
保存了几个大的String。然后分析出是某些日志太大导致的,减少对应日志信息就可以了
网友评论