文章目录
一.OOM存在的几种情况.
除了程序计数器外,虚拟机内存的其他几个运行时区域都可能发OOM.只不过堆内存溢出最为常见.
1, 堆内存溢出
一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess
java堆用于存储对象实例,我们只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。
2, 虚拟机栈和本地方法栈溢出
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常
这里需要注意当栈的大小越大可分配的线程数就越少。
3, 运行时常量池溢出
异常信息:java.lang.OutOfMemoryError:PermGen space
如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法。该方法的作用是:如果池中已经包含一个等于此String的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。由于常量池分配在方法区内,我们可以通过
-XX:PermSize和-XX:MaxPermSize
限制方法区的大小,从而间接限制其中常量池的容量。
4, 方法区溢出
异常信息:java.lang.OutOfMemoryError:PermGen space
方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。
方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定条件是很苛刻的。在经常动态生成大量Class的应用中,要特别注意这点。
二.几种问题的常见排查思路
1.堆内存溢出检查.
(1).在程序启动时我们可以设置以下参数以便在内存溢出时生成dump文件:
-XX:Xms20m;
-XX:Xms20m:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D:/(注意这里没有加号)
以上的命令是已经发生内存溢出的时候我们配置让其输出溢出信息.在实际工作中不可能等到真正溢出再去处理,会实时监控数据.
(2).使用jmap实时查看内存情况/导出dump文件
一般来说有以下几步:
(1).jps -l:找到当前进程id.
(2).jmap -heap pid:查看当前进程的数据.(老年代新生代的使用情况)
(3).jmap -dump:format=b,file=app.hprof pid(导出该进程的hprof的文件,关于内存情况的映射)
说明:file后面跟的是文件名称,文件路径自动生成,显示在cmd中,去对应路径中找文件即可.
2.Java进程CPU占用过高检查.
3.Java进程内存泄漏.
主要使用 jstat 命令查看GC情况.
jstat -gc pid [interval]
各个参数意义如下:
三.JVM调优
jvm 调优,调的是稳定,并不能带给你性能的大幅提升。服务稳定的重要性就不用多说了,保证服务的稳定,gc 永远会是 Java 程序员需要考虑的不稳定因素之一。复杂和高并发下的服务,必须保证每次 gc 不会出现性能下降,各种性能指标不会出现波动,gc 回收规律而且干净,找到合适的 jvm 设置。Full gc 最会影响性能,根据代码问题,避免 full gc 频率。可以适当调大年轻代容量,让大对象可以在年轻代触发 yong gc,调整大对象在年轻代的回收频次,尽可能保证大对象在年轻代回收,减小老年代缩短回收时间.
1.几个常用工具.
2.命令示例.
3.调优-设置新生代和老年代内存比例.
1.这个参数对系统性能以及GC行为有很大影响,
新生代一般设置整个堆空间的1/3-1/4.
-Xmn10m: 设置新生代初始大小为10m.
2.-XX:SurvivorRatio:用来设置新生代中eden空间和from/to空间的比例.
也就是-XX:SurvivorRatio=eden/from=eden/to
举例:-Xmn10m -XX:SurvivorRatio=2 那么eden5m,from和t各2.5m
3.-XX:NewRatio=老年代/新生代
设置老年代和新生代比例.
基本策略:
尽可能将对象预留在新生代,减少老年代的GC次数.
补充:
oracle并没有将所有的堆参数形成一个文档,如果我们想查阅某个参数的话,可以通过命令查看.
java -XX:+PrintFlagsFinal -version
如果需要查哪方面的参数,直接在后面grep即可.
本文转载自:分析解决OOM与JVM参数调优