JVM调优大全及实战总结

文章目录

      • JVM 类型
      • JVM 内存中的概念及分区
        • 在JDK6及之前的版本
        • JDK7及之后的版本
      • 为什么叫Hot Spot?
      • 性能调优的程序
      • 性能调优的标准:
      • 性能调优的工具:
        • 监控工具:
        • 分析工具:
        • JVM自带工具
      • GC基础
      • GC日志
      • GC 调优
      • HotSpot VM的Heap布局
      • 对象在不同代的移动
      • 虚拟机调优
      • 总体设置原则:
      • 内存泄漏

JVM 类型

Java Virtual Machine 是Java 的运行环境。
常用的JVM类型包括:

  • HotSpot VM
     是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。
  • JRockit JVM: 由Oracle提供的
  • IBM JVM : IBM出品的

JVM 内存中的概念及分区

程序要跑的快,是需要足够的空间。但是内存空间总是有限的, 解决办法就是把不需要的东西腾地方并清除掉。
JVM具备垃圾自动回收功能,其如何进行垃圾回收并保持整体的性能呢?
JVM将内存空间切分为不同的区块, 经常会看见如下概念:

  1. Young: 年轻代
  2. Eden: 伊甸区
  3. Survivor0: 幸存者区0
  4. Survivor1: 幸存者区1
  5. Tenured:老年代, 也称作Old Gen
  6. Perm:永久代
  7. 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的编译器。

性能调优的程序

  1. 测试, 使用SopaUI或是LoadRunner等工具
  2. 监控, 使用Top , VisualVM等
  3. 量测: 使用Head Dumps等
  4. 调优: 参数、代码

性能调优的标准:

  • 内存
  • 启动时间
  • 吞吐量 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基础

  1. 一般对象Typical object (Young object), 在创建之后很快就被回收,像一些本地的对象
  2. 已经存活了一段时间的旧对象会继续存活一段时间
  3. Only a few references from old objects to
    young objects exist

GC日志

在weblogic 下查看gclog.1.txt文件
可以看到
-内存使用、空闲状况等
-GC发生的频率和花费的时间等

GC日志参数:
常用:

  1. -XX:+PrintGCTimeStamps
    或者 -XX:+PrintGCDateStamps
  2. -XX:+PrintGCDetails
    选用:
  3. -Xloggc: 日志文件名
  4. 日志滚动配置
    -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

  1. 使用JConsole/VisualVM执行GC
    点击"Perform GC"

  2. jmap查看
    jmap -histo:live

统计方法二:
GC log
GC Log 可以统计:

  1. LDS
  2. 最大的永久代大小
  3. 延迟状况

总体设置原则:

  1. 设置 -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

  1. 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配置越大,创建的线程数量就越小。
如果需要增加:办法有:

  1. MaxProcessMemory
    修改OS设定, 或者使用64位的系统
  2. JVMMemory
    减少JVM的内存使用
  3. ThreadStackSize
    减少单一线程执行的栈的大小

未完, 待续…

你可能感兴趣的:(java,jvm,java,开发语言,servlet,hdfs)