文章目录
JVM 类型
Java Virtual Machine 是Java 的运行环境。
常用的JVM类型包括:
- HotSpot VM
是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。 - JRockit JVM: 由Oracle提供的
- IBM JVM : IBM出品的
JVM 内存中的概念及分区
程序要跑的快,是需要足够的空间。但是内存空间总是有限的, 解决办法就是把不需要的东西腾地方并清除掉。
JVM具备垃圾自动回收功能,其如何进行垃圾回收并保持整体的性能呢?
JVM将内存空间切分为不同的区块, 经常会看见如下概念:
- Young: 年轻代
- Eden: 伊甸区
- Survivor0: 幸存者区0
- Survivor1: 幸存者区1
- Tenured:老年代, 也称作Old Gen
- Perm:永久代
- G1:Garbage First Garbage Collector
在JDK6及之前的版本
Young = Eden + Survivor1+ Survivor2
JDK7及之后的版本
JDK7使用了G1。
G1 GC由Young Generation和Old Generation组成。G1将Java堆空间分割成了若干个Region,即年轻代/老年代是一系列Region的集合,这就意味着在分配空间时不需要一个连续的内存区间,即不需要在JVM启动时决定哪些Region属于老年代,哪些属于年轻代。因为随着时间推移,年轻代Region被回收后,又会变为可用状态(后面会说到的Unused Region或Available Region)了
IBM的JVM虽然也有Nursery(Allocate+Survivor)+Tenured 的概念, 但实际上是一整块划分。
所以对于IBM的JVM来说, -Xms和-Xmx的初始值设置成不一样会有点意义。
为什么叫Hot Spot?
Java执行先将 .java编译成平台通用的 .class字节码文件, 这些字节码文件会被JVM逐条执行,速度相对较慢。对于一些运行频繁的代码,也就是Hot Spot Code(热点代码)。为了提高热点代码的执行效率,在运行时,虚拟机的JIT 编译器将会把这些代码编译成与本地平台相关的机器码,并进行各层次的优化。
注意 JRockit没有JIT的编译器。
性能调优的程序
- 测试, 使用SopaUI或是LoadRunner等工具
- 监控, 使用Top , VisualVM等
- 量测: 使用Head Dumps等
- 调优: 参数、代码
性能调优的标准:
- 内存
- 启动时间
- 吞吐量 TPS
- 响应时间
性能调优的工具:
监控工具:
在线: JRMC(JRockit), VisualVM(Hotspot)
离线: GC Logs, GC Viewer , JFR
分析工具:
- Most IDE’s(JVMTI)
- MAT (Heap dumps)
- JRMC
- VisualVM
- 第三方, 类似JProfiler, YourKit
JVM自带工具
- jps -v
列出当前用户的所有Java进程, 可以显示进程Id和启动路径等信息。
-jinfo
列出Java进程更多的信息
-jstack
提供进程的statck dump信息。
对于线程Dump分析有用。
-jstat
根据参数显示不同的JVM统计, 例如:
jstat -gcutil -v -h5 10000 20
显示GC的利用百分比。
在GC的日志关闭的状况下适用。
注意: 在Windows下无法使用这个命令。
GC基础
- 一般对象Typical object (Young object), 在创建之后很快就被回收,像一些本地的对象
- 已经存活了一段时间的旧对象会继续存活一段时间
- Only a few references from old objects to
young objects exist
GC日志
在weblogic 下查看gclog.1.txt文件
可以看到
-内存使用、空闲状况等
-GC发生的频率和花费的时间等
GC日志参数:
常用:
- -XX:+PrintGCTimeStamps
或者 -XX:+PrintGCDateStamps - -XX:+PrintGCDetails
选用: - -Xloggc: 日志文件名
- 日志滚动配置
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=10M
GC 调优
最常使用的GC参数:
-垃圾回收策略: 例如:non-generational, concurrent, parallel GC, deterministic,等
-GC并行:serial , parrallel, concurrent
-各个代的大小
最常使用GC诊断参数
-gc 日志 (-verbose:gc)
-日志层级: 例如: -XX:+PrintGCDetails(Hotspot)
-Xverbose:gcpause(JRockit)
-日志文件: -Xloggc: (Hotspot), -Xverboselog: (JRockit)
HotSpot VM的Heap布局
32位操作系统最大内存 2^32 = 4G
2G 内存, JVM最大 1.5
3G 内存: 2.6~2.7 G(Weblogic)
对象在不同代的移动
新创建的对象放入 Eden,
在Minor GC 的时候,有些对象移动到两个幸存区。
老年代放置一些长久的对象
永久代放置Class的信息。
一个对象在放入到老年代之前, 会在S0,S1之间来来回回三次。
Runtime Stack会link到使用的对象, 对于没有到达的对象,就会清除。
虚拟机调优
JVM不能使用到所有的内存, 还要预留空间给其他。不能超过物理内存的大小。
最大(80%~90%)
减少线程栈的空间给heap -xss: 128k
如何决定年轻代的空间大小:
- minor GC的频率
- minor GC回收的对象数量
老年代大小:
- 维护系统稳定运行的存活数据大小
-最小化 major GC的频率
原则:在年轻代最大化回收对象,最小化full gc的频率。
调整任何代的空间大小,需要Full GC.
比较好的设置是初始化和最大内存设置相同: -Xmx=-Xms
-可以预防Xms 到Xmx空间大小导致的full GC
-性能比较好
永久代的大小
-XX:PermSize=-XX:MaxPermSize
永久代占用的大小很难预估, 动态Class
设置足够大预防 PermGen的OOME错误
-XX:NewSize=-XX:MaxNewSize
一般使用-Xmn配置
Live Data Size(LDS)-存活数据大小统计
统计方法一:
统计之前,执行full GC
-
使用JConsole/VisualVM执行GC
点击"Perform GC" -
jmap查看
jmap -histo:live
统计方法二:
GC log
GC Log 可以统计:
- LDS
- 最大的永久代大小
- 延迟状况
总体设置原则:
- 设置 -Xms 和-Xmx是 LDS的3到4倍。
2.设置-XX:PermSize和-XX:MaxPermSize为最大永久代空间的1.2 到1.5倍
新生代 设置成 LDS的1到1.5倍
永久代设置成 LDS的2到3倍
新生代的空间大约设置成堆空间的1/3 - 1/4
For LDS of 512m : -Xmn768m -Xms2g -Xmx2g
内存泄漏
- 出现OutOfMemory错误
-长时间存活对象使用的空间一直在增加 - 一般问题出在应用程式
常见错误:
1.java.lang.OutOfMemoryError: Java heap space
堆空间满了
配置-Xms 和-Xmx
- java.lang.OutOfMemoryError: PermGen space
永久代空间满了
配置 MinPermGen 和MaxPermGen
3.java.lang.OutOfMemoryError:unable to create new native thread
(MaxProcessMemory-JVMMemory-ReservedOsMemory)/(ThreadStackSize) = Number of threads
MaxProcessMemory: 操作系统给一个进程的内存
JVMMemory: JVM内存 Heap+PermGen
ReservedOsMemory: 保留给操作系统的内存
ThreadStackSize: 线程内存的大小 -Xss
TreadStackSize
默认 325 , -Xms, -Xmx配置越大,创建的线程数量就越小。
如果需要增加:办法有:
- MaxProcessMemory
修改OS设定, 或者使用64位的系统 - JVMMemory
减少JVM的内存使用 - ThreadStackSize
减少单一线程执行的栈的大小
未完, 待续…