JVM
一、JVM内存模型
堆内存
1、JVM实质上分为三大块:
年轻代(YoungGen),年老代(Old Memory),及持久代(Perm,在Java8中被取消)
2、垃圾回收GC,分2种:
Minor GC,可以可以称为YGC(年轻代);
Major GC,又称为FullGC(老年代);
3、对象存储过程:
刚被new出来的时候,放到Eden区。
Eden区空间不足,发生YGC,没有被任何其他对象所引用的对象将会从内存中被清除,
还被其他对象引用的则放到幸存者区(幸存者1区和幸存者2区其中一个)。
幸存者区多次没有被清除的对象,则会被移到老年代区。
当老年代区域被占满的时候,则会发送FullGC。这时只允许GC进程进行垃圾回收。
4、无论是YGC或是FullGC,都会导致程序会停止运行stop-the-world,执行一次时间
在40秒至3分钟的fullgc,部分web或socket程序,当终端连接的时候会
报connetTimeOut或readTimeOut异常,
5、从JVM调优的角度来看,我们该尽量避免发生YGC或FullGC,或者使得YGC和FullGC的时间
足够的短。
JDK1.8之后,之前的永久代区被元空间区取代,元空间区不在JVM内存中,在操作系统内存中
内存溢出:旧对象仍然保持引用时不断创建新对象,使得堆内存空间满至溢出的现象
内存泄漏:旧对象已经无实际职责,但是没有将其引用设置为null,导致其无法被回收,
一直占据内存空间的现象
内存泄漏会导致内存的实际可用空间不断变小,最终引发内存溢出。
1. JVM Java进程
2. JVM (堆空间) HBase
新生代 1/3 老年代 2/3 永久代(静态,常量)
eden survivor(from) survivor(to)
8 1 1
ParNewGC ConcMarkSweepGC
”-Xmx8g -Xms8G -Xmn128m -XX:UseParNewGC -XX:UseConcMarkSweepGC - XX:CMSInitiatingOccupancyFraction=70 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:$HBASE_HOME/logs/gc-${hostname}-hbase.log”
hbase-env.sh
export HBASE_REGIONSERVER_OPTS=”-Xmx8g -Xms8G -Xmn128m -XX:UseParNewGC -XX:UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:$HBASE_HOME/logs/gc-${hostname}-hbase.log”
二、 运行时数据区
三、JVM类加载
2.1 类加载过程
验证:
文件格式,符号引用,字节码,元数据
准备:
对静态变量分配内存,使用默认值(特殊:被final修饰的static变量在编
译期进入常量池)
解析:
将符号引用(用符号指向目标的指针)转化为直接引用(指针,相对偏移量,
间接指向目标的句柄)
初始化:
对当前类父类或者超类对其实例化(不完全加载),对静态变量进行赋
值,对成员变量赋予默认值
2.2、类加载器
- 加载过程----通过类加载器将格式为.class的文件加载入JVM。
2.2.1 启动类加载器(Bootstrap)
C++编写 加载的时候,根据类的权限定名读取核心类库(以java、javax、sun,
特殊的(rt.jar))
---将核心类库JDK加载到 虚拟机内存中,
为保证虚拟机安全(),没有父类。
2.2.2 拓展类加载器(Extension)
java编写 父类 null
读取外部引入类库(通常为项目中引入的第三方jar包)
2.2.3 系统类加载器(System)
(application)java编写
父类 拓展类加载器
读取classpath下的类
2.2.4 自定义类加载器
父类 系统类加载器
2.3、双亲委派机制
当JVM需要一个类的类信息时,首先从调用loadclass方法从内存中尝试读取该类信息,
读取时从自定义类加载器逐级向上,直至读取到为止。如果未能读取,则从bootstrap类加
载器开始调用findclass方法尝试进行加载,如果不能读取则逐级向下委派,如果都不能读
取,则抛出ClassNotFoundException。
类加载的两种方式:
显式:一般的类的加载。
隐式
Class.forName this.getClass().getClassLoader().loadclass()
双亲委派机制的破坏者:
线程上下文类加载器---读取rt.jar中的接口实现方法
举例:JDBC中对驱动的加载,使用的显示加载,因为该类无法被双亲委派隐式加载
- 反编译
四、虚拟机配置
4.1 IDEA虚拟机配置
-Xms128m
Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,
开发测试机JVM可以保留默认值
-Xmx750m
java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理
内存大小及计算机内其他内存开销而定
-XX:ReservedCodeCacheSize=240m
预留保存代码的内存空间大小。
-XX:+UseConcMarkSweepGC
老年代使用 CMS 垃圾回收策略(并发标记清除)
-XX:SoftRefLRUPolicyMSPerMB=50
意思是最近最少被引用的软引用 将在50秒后被JVM清除。单位为秒。
-ea
ea 开启断言 -da 禁止断言
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
如果在使用ipv4的机器上运行启用了ipv6的系统,那么此参数设为true才
能获取机器的完整机器名
-Djdk.http.auth.tunneling.disabledSchemes=""
根据域名自动下载https服务端发送过来的证书并保存成文件
-XX:+HeapDumpOnOutOfMemoryError
当堆内存空间溢出时输出堆的内存快照
-XX:-OmitStackTraceInFastThrow
省略异常栈信息从而快速抛出,JVM对一些特定的异常类型做了Fast Throw优化,
如果检测到在代码里某个位置连续多次抛出同一类型异常的话,C2会决定用Fast Throw方
式来抛出异常,而异常Trace即详细的异常栈信息会被清空。这种异常抛出速度非常快,
因为不需要在堆里分配内存,也不需要构造完整的异常栈信息
4.3 虚拟机配置分析
java
-server
-Xms4G -Xmx4G -Xmn2G
-XX:SurvivorRatio=1
-XX:+UseConcMarkSweepGC
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1100
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-jar c1000k.jar&
-Xms4G 是指: JVM启动时整个堆(包括年轻代,年老代)的初始化大小。
-Xmx4G 是指: JVM启动时整个堆的最大值。
-Xmn2G是指:年轻代的空间大小,剩下的是年老代的空间。
-XX:SurvivorRatio=1是指:年轻代空间中2个Survivor空间与Eden空间的大小比例。
此处为1:1:1,算法如下:比如整个年轻代空间为2G,如果比例为1,那么2/3,
则S0/S1/Eden的空间大小是同样的,为666M。
该值不设置,则JDK默认为比例为8,那么是1:1:8,通过上面的算法可以得出S0/S1的大小。
我们可以看到官方通过增大Eden区的大小,来减少YGC发生的次数,但有时我们发现,
虽然次数减少了,但Eden区满的时候,由于占用的空间较大,导致释放缓慢,
此时stop-the-world的时间较长,因此需要按照程序情况去调优。
-XX:+UseConcMarkSweepGC是指:使用GC的回收类型。这里是CMS类型,JDK1.7以后推荐
使用+UseG1GC,被称为G1类型(或Garbage First)的回收器
再服务器上执行:jstat -gc 15016 1000,看到每1秒钟java进程号为15016的GC回收情况
root@sxxd ]# jstat -gc 1500 1000
S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
699008.0 699008.0 29980.4 0.0 699136.0 116881.6 2097152.0 660769.4 21248.0 20071.0 354 54.272 0 0.000 54.272
699008.0 699008.0 29980.4 0.0 699136.0 118344.8 2097152.0 660769.4 21248.0 20071.0 354 54.272 0 0.000 54.272
699008.0 699008.0 29980.4 0.0 699136.0 119895.5 2097152.0 660769.4 21248.0 20071.0 354 54.272 0 0.000 54.272
699008.0 699008.0 29980.4 0.0 699136.0 121383.1 2097152.0 660769.4 21248.0 20071.0 354 54.272 0 0.000 54.272
- 解释
S0C 是指:Survivor0区的分配空间
S0U 是指:Survivor1区的已经使用的空间
EC是指: Eden区所使用的空间
EU是指:Eden区当前使用的空间
OC是指:老年代分配的空间
OU是指:老年代当前使用的空间
PC是指:持久待分配的空间
PU是指:持久待当前使用的空间
YGC是指:年轻代发生的次数,这里是354次
YGCT是指:年轻代发送的总时长,这里是54.272秒,因此每次年轻代发生GC,
即平均每次stop-the-world的时长为54.272/354=0.153秒。
FGC是指:年老代回收的次数,或者成为FullGC的次数。
FGCT是指:年老代发生回收的总时长。
GCT是指:包括年轻代YGC及年老代FGC的总时间长。
- 通常
- 当EU即将等于EC的时候,此时发生YGC,因此YGC次数+1,YGCT时间增加。
- 发生YGC的时候,如果S0U或S1U区如果有任意一个区域为0的时候,此时YGC的速度很快,相反如果S0U或者S1U中都有数据,或相对满的时候,此时YGC的时间边长,这就是因为S0/S1及Eden区的比例问题导致的
- 经过调优,使得YGC的次数非常少,时间非常快,很长时间,数天都不会发生FGC,此时JVM的调优算是一个好的结果。
4.3 GC日志分析
Full GC:对整个堆内存空间的一次垃圾回收
GC:对年轻代空间的一次垃圾回收
Allocation Failure:“分配失败”,即为新对象分派内存不够
System.gc():执行该方法触发的GC