java内存模型
java内存空间主要包括以下几个部分:方法区、堆内存、虚拟机栈、本地方法栈
- 方法区:主要存放已被加载的类信息,常量,静态变量等。
- 堆内存:Java堆是JVM所管理的最大一块内存空间,几乎所有的对象实例都会在这里分配内存
- 虚拟机栈:每个线程私有。生命周期与线程相同,主要用于存储局部变量表,操作数栈,动态链接,方法出口等
- 本地方法栈:与虚拟机栈类似,主要为JVM使用到的Native方法服务
java内存溢出的根源
在以上四个区域中,内存溢出主要发生在堆内存和方法区中。其中,堆内存溢出最为常见。它主要由以下两种原因引起:
- 内存泄露:程序中某个部分的内存未能被释放掉,这块内存随着时间的推移,会逐渐积累,最终导致内存溢出
- 当程序需要申请的内存超过JVM堆的最大限制时,会抛出内存溢出错误
排查内存溢出思路
- 检查代码:找出可能导致内存泄露的代码段,如未关闭的资源,长生命周期对象持有短生命周期对象的引用等
- 使用内存分析工具:内存分析工具(如JProfiler, MAT, VisualVM等)可以对Java堆进行深入的分析,找出内存使用的热点
- 生成堆转储文件:当发生内存溢出时,可以生成堆转储文件进行分析,这可以通过-XX:+HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath参数配置JVM实现。
常用命令
查看内存使用情况和gc情况
/opt/infosec/NetSeal/jdk1.8.0_121/bin/jstat -gc -h1 pid 1s
其对应的指标含义如下:
- S0C 年轻代中第一个survivor(幸存区)的容量 (字节)
- S1C 年轻代中第二个survivor(幸存区)的容量 (字节)
- S0U 年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
- S1U 年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
- EC 年轻代中Eden(伊甸园)的容量 (字节)
- EU 年轻代中Eden(伊甸园)目前已使用空间 (字节)
- OC Old代的容量 (字节)
- OU Old代目前已使用空间 (字节)
- MC 方法区大小
- MU 方法区目前已使用空间 (字节)
- CCSC 压缩类空间大小
- CCSU 压缩类空间已使用大小
- YGC 从应用程序启动到采样时年轻代中gc次数
- YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)
- FGC 从应用程序启动到采样时old代(全gc)gc次数
- FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
- GCT 从应用程序启动到采样时gc用的总时间(s)
查看jvm信息 主要是最大内存
/opt/infosec/NetSeal/jdk1.8.0_121/bin/jinfo -flags 968687
打印线程信息
/opt/infosec/NetSeal/jdk1.8.0_121/bin/jcmd <pid> Thread.print
gc
手动释放gc
/opt/infosec/NetSeal/jdk1.8.0_121/bin/jcmd <pid> GC.run
执行完之后,可以去查询此时的内存
当OU和OC 相差很多时,说明手动执行GC成功,不存在内存泄露,不存在未被释放的对象,当OU和OC相差微小时,即没有可用内存,会发生内存溢出