JVM内存性能定位
有点乱的一篇记录,想到哪敲到哪了。。。
堆和栈
首先,栈(stack)和堆(heap)都是Java用来在RAM中存放数据的地方。根据 JVM 规范,JVM 内存共分为java栈(虚拟机栈VM Stack)、堆(Heap)、方法区(Method Area)、程序计数器(Program Counter Register)、本地方法栈(Native Method Stack)五个部分。
堆:用来存储程序中的一些对象,比如你用new关键字创建的对象,它就会被存储在堆内存中,但是这个对象在堆内存中的首地址会存储在栈中
栈:在jvm中栈用来存储一些对象的引用、局部变量以及计算过程的中间数据,在方法退出后那么这些变量也会被销毁。它的存储比堆快得多,只比CPU里的寄存器慢
栈内存在JVM中默认是1M,可以通过参数进行设置:-Xss
最小堆内存在JVM中默认物理内存的64分之1,最大堆内存在JVM中默认物理内存4分之一,且建议最大堆内存不大于4G,并且设置-Xms=-Xmx避免每次GC后,调整堆的大小,减少系统内存分配开销:-Xms
、-Xmx
.
JVM堆内存与GC
在JVM里的内存空间,从大的层面划分,主要有新生代空间(Young)和老年代空间(Old),其中Young空间,又有1个Egen区,和2个Survivor区
Eden区域是用来存放使用new或者newInstance等方式创建的对象,默认都是存放在Eden区,除非这个对象太大,或者超过了设定的阈值-XX:PretenureSizeThresold,这样的对象会被直接分配到Old区域。
2个Survivor(幸存)区,一般称S0,S1,理论上他们是一样大的,解释一下,他们是如何工作的:
在不断创建对象的过程中,Eden区会满,这时候会开始做Young G也叫Minor GC,而Young空间的第一次GC就是找出Eden区中,幸存活着的对象,然后将这些对象,放到S0,或S1区中的其中一个, 假设第一次选择了S0,它会逐步将活着的对象拷贝到S0区域,但是如果S0区域满了,剩下活着的对象只能放old区域了,接下来要做的是,将Eden区域 清空,此时时候S1区域也是空的。
当第二次Eden区域满的时候,就将Eden区域中活着的对象+S0区域中活着的对象,迁移到S1中,如果S1放不下,就会将剩下的部门,放到Old区域中,只是这次对象来源区域增加了S0,最后会将Eden区+S0区域,清空。
第三次和第四次依次类推,始终保证S0和S1有一个是空的,用来存储临时对象,用于交换空间的目的,反反复复多次没有被淘汰的对象,将会放入old区域中,默认是15次。具体的交换过程就和上图中的信息相似。
S0和S1一般多大,靠什么参数来控制,有什么变化?
一般来说很小,我们大概知道它与Young差不多相差一倍的比例,设置的的参数主要有两个:
-XX:SurvivorRatio=8
-XX:InitialSurvivorRatio=8
第一个参数是Eden和Survivor区域比重,注意是一个Survivor的的大小,如果将其设置为8,则说明Eden区是一个Survivor区的8倍,换句话说S0或S1空间是整个Young空间的1/10,剩余的80%由Eden区域来使用。
第二个参数是Young/S0的比值,当其设置为8时,表示s0或s1占整个Young空间的12.5%。
一个对象每次Minor Gc时,活着的对象都会在s0和s1区域转移,经过经过Minor GC多少次后,会进入Old区域呢?
默认是15次,参数设置-XX:MaxTenuringThreshold=15,计数器会在对象的头部记录它交换的次数
FULL GC
发生FULL GC的时候,意味着JVM会安全的暂停所有正在执行的线程(Stop The World),来回收内存空间,在这个时间段内,所有除了回收垃圾的线程外,其他有关JAVA的程序,代码都会静止,反映到系统上,就会出现系统响应大幅度变慢,卡机等状态。
内存分析
线程阻塞
关于线程阻塞,在之前定位linux最耗CPU时已经有提过:Jstack定位线程阻塞
这边提供一个分析工具,当使用jstack pid > 1.log
生成堆栈日志之后,使用tda
工具进行分析
jstat查看gc
jstat -gccause pid 5000
,每隔5s刷新一次,查看GC信息,
1 | [root@iZuf61um4k0dww403xbmgpZ ~]# jstat -gccause 1270 5000 |
其中FGC
代表程序启动至今的FULL GC次数
jmap分析GC
jmap -heap PID
可以直接看到当前堆内存信息,包含各区域使用率
jmap -histo:live PID | head -10
打印当前java堆活跃的各个对象的数量、大小
jmap -dump:live,format=b,file=dump.hprof PID
生成dump文件(堆栈)
生成的dump文件(dump.hprof),可以用MAT(MemoryAnalyzer
)工具进行堆栈分析
打印GC日志
最后,可以通过启动应用时加上GC打印的设置,直接将GC打印到文件中进行分析:
1 | -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:/root/log/gclogs |
分析用工具:gcviewer-1.36-SNAPSHOT
gcviewer度娘盘地址(提取码:cvhs)
工具启动方式:java -jar gcviewer-1.36-SNAPSHOT.jar
(文件目录下执行)
参考文章
工具使用教程
利用mat定位内存泄漏原因
java GC日志查看gcviewer
TDA进行java线程dump分析
java线程Dump分析工具–jstack
Java GC日志查看