JVM基础

1 JDK架构图

 官网:jdk1.8 hotspot虚拟机相关概念官网

2 Java从编码到执行

3 JVM

1 跨语言的平台

2 JVM虚构出来的一台计算机

JVM虚拟机规范

  • 字节码指令集(汇编语言)
  • 内存管理:栈 堆 方法区等

4 JDK JRE JVM

5 JVM虚拟机种类

  • Hotspot
    - oracle官方
  • Jrockit
    - BEA,曾经号称最快的JVM
    - 被Oracle收购,合并于hotspot
  • J9
    - IBM
  • Microsoft VM

6 类加载

1 class生命周期

1 加载

加载指的是将类的二进制class文件读入到内存,并为之创建一个java.lang.Class对象

2 链接

  • 验证
    验证阶段用于检验被加载的类是否有正确的内部结构。主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
  • 准备
    类准备阶段负责为类的静态变量分配内存,并设置默认初始值
  • 解析
    将类的二进制数据中的对象指向引用地址

3 初始化

初始化是为类的静态变量赋真正的值

2 类加载时机

主动:

  • 创建类的实例,即new一个对象
  • 访问某个类或接口的静态变量,或者对该静态变量赋值

  • 调用类的静态方法

  • 反射(Class.forName("com.ly.load"))

  • 初始化一个类的子类(会先初始化父类)

  • JVM启动时标明的启动类

*对于一个final类型的静态变量,如果该变量的值在编译时就可以确定下来。Java编译器会在编译时直接把这个变量出现的地方替换成它的值,因此即使程序使用该静态变量,也不会导致该类的初始化。反之,如果final类型的静态Field的值不能在编译时确定下来,则必须等到运行时才可以确定该变量的值,如果通过该类来访问它的静态变量,则会导致该类被初始化

被动:

  • 引用该类的静态常量,注意是常量,不会导致初始化,但是也有意外,这里的常量是指已经指定字面量的常量,对于那些需要一些计算才能得出结果的常量就会导致初始化,比如:

    public final static int NUMBER = 5; //不会导致类初始化.被动使用
    public final static int RANDOM = new Random().nextInt(); //会导致类的初始化.主动使用
  • 构造某个类的数组时不会导致该类的初始化,比如:

    Student[] students = new Student[10];
    

3 类加载器

双亲委派机制

加载过程

7 运行时数据区

1 JavaStacks

每个java线程有自己的虚拟机栈,虚拟机栈中存有栈帧,每个方法都是一个独立的栈帧

2 ProgramCounter

存放指令运行到哪的计数器

3 MethodArea

  • Perm Space (<1.8)
    字符串常量位于PermSpace
    FGC不会清理
    大小启动的时候指定,不能变

  • Meta Space (>=1.8)
    字符串常量位于堆
    会触发FGC清理
    不设定的话,最大就是物理内存

4 NativeMethodStacks

调用JNI时的栈

5 DirectMemory

JVM可以直接访问的内核空间的内存 (OS 管理的内存)
NIO , 提高效率,实现zero copy

6 Heap

各个线程运行时共享的空间

7 各数据区之间的联系

8 堆内存逻辑分区

新生代大量死去,少量存活,采用复制算法
老年代存活率高,回收较少,采用标记压缩清除或者标记清除算法

1 一个对象从出生到死亡

1 对象进入栈

一个对象的创建,会先到栈上分配内存,如果确定一个对象的作用域不会逃逸出方法之外,那可以将这个对象分配在栈上,这样,对象所占用的内存空间就可以随栈帧出栈而销毁。在一般应用中,不会逃逸的局部对象所占的比例很大,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了,无须通过垃圾收集器回收,可以减小垃圾收集器的负载。

2 对象进入年轻代

如果不能分配到栈上,对象会分配在堆上,而堆是全局共享的。因此在同一时间,可能会有多个线程在堆上申请空间。因此,每次对象分配都必须要进行同步(虚拟机采用CAS配上失败重试的方式保证更新操作的原子性),而在竞争激烈的场合分配的效率又会进一步下降。JVM使用TLAB来避免多线程冲突,在给对象分配内存时,每个线程使用自己的TLAB,这样可以避免线程同步,提高了对象分配的效率,TLAB位于Eden区,参数-XX:+UseTLAB可开启TLAB,默认是开启的。TLAB空间的内存非常小,缺省情况下仅占有整个Eden空间的1%,当然可以通过选项-XX:TLABWasteTargetPercent设置TLAB空间所占用Eden空间的百分比大小。Eden区满了会YGC,存活对象到survivor1区

3 对象进入老年代

默认规则
-XX:MaxTenuringThreshold=X X默认是15,15的含义是从eden-->survivor 对象年龄+1,survivor-->eden 对象年龄+1,直到年龄达到15后开始进入老年区。
动态规则
Hotspot遍历所有对象时,按照年龄从小到大对其所占用的大小进行累积,当累积的某个年龄大小超过了survivor区的一半时,取这个年龄和MaxTenuringThreshold中更小的一个值,作为新的晋升年龄阈值。

描述:所有的新生代首先会在Eden区进行内存分配,当Eden区满时会进行一次Minor GC操作,将Eden区进行回收,此时判断存活的对象会被复制进入Survivor from区(年龄加1),对于大对象直接进入老年代,实际上是为了保证Eden区具有充足的空间可用的一种策略,采用-XX:PretenureSizeThreshold参数可以设置多大的对象可以直接进入老年代内存区域。对于长期存活的对象直接进入老年代,实际上是对Eden区到Survivor区过度的一种策略,是为了保证Eden区到Survivor区不会频繁的进行复制一直存活的对象且对Survivor区也能保证不会具有太多的一直占据的内存,采用-XX:MaxTenuringThreshold=数字 参数可以设置对象在经过多少次GC后会被放入老年代(年龄达到设置值,默认为15)。对于动态对象年龄判断,实际上是对Survivor区的一种策略,是为了保证Survivor区具有充足的空间用于分配,动态对象年龄只判断Survivor区是否存在相等对象年龄的对象是否超过Survivor from/to的一半时,直接将超过的对象放入老年代。对于空间分配担保实际上是针对老年代,为了保证老年代的内存区域具有充足的空间,不至于内存溢出的情况出现,在发生MinorGC之前,JVM会判断之前每次晋升到老年代的平均大小是否大于老年代剩余空间的大小,若大于则进行full GC(即回收所有区域),若小于,则还需要查看一个参数HandlePromotionFailure,即是否允许担保失败,因为实际上进入老年代的对象大小在GC前是未知的,这也是为什么采用之前晋升的平均值来进行判断担保,也就是说只是一种预测,并不能代表真实就是有这么多对象晋升,所以若不允许担保失败,即保守的人为一定会有超过剩余老年代区域的对象存入,则还是进行Full GC,否则,进行Minor GC。

4 GC

1 垃圾

什么是垃圾?

没有引用指向的任何对象都是垃圾

2 找垃圾的几种方式

引用计数法

。    

存在问题:存在循环引用的时候永远清不掉,存在垃圾碎片

根可达算法

3 GC算法

1 标记清除法(Mark Sweep)

优点:算法相对简单,存活对象比较多的情况下效率比较高
缺点:两遍扫描(先标记再清除),效率低,容易产生碎片

2 拷贝(Copying)

优点:适用于存活对象较少的情况,只扫描一次效率高,没有碎片
缺点:空间浪费,需要调整对象引用

3 标记压缩法(Mark-Compact)

优点:不会产生碎片,方便内存分配,不会产生内存浪费减半
缺点:扫描两次(先标记再清除),需要移动对象,效率偏低

4 垃圾回收器

常见组合:

- Serial + Serial Old
- ParNew + CMS + Serial Old
- Parallel Scavenge + Parallel Old

1 Serial

*安全点:JVM在进行可达性分析时,需要枚举遍历GC Roots,如果针对引用链挨个遍历,在几百上千兆的内存大小遍历也是非常耗时间的。所以HotSpot虚拟机用OopMap(Ordinary Object Pointer map集合)来记录对象内的引用关系,只有在特殊的指令或者特定的位置才会产生或者更新OopMap,这个特定的位置即为安全点。

*STW:除JVM工作线程外,中断所有用户进程,程序全局暂停;本质是通过挂起线程来阻断对JVM的操作。回收垃圾过程中,为了保证标记过程中引用关系的一致性,需要stw操作。

特点:

  • 采用复制算法
  • 单CPU效率最高
  • 最悠久、最简单的垃圾回收器
  • 单线程工作垃圾回收器

2 SerialOld

特点:

  • 采用标记整理算法(标记清除压缩法)
  • 单线程工作的回收器
  • 作为CMS的后备元,在并发收集发生 Concurrent Mode Failure的时候使用

3 Parallel Scavenge

特点:

  • 采用复制算法
  • 多线程的回收器

4 Parallel old

特点:

  • 采用标记整理算法
  • 多线程的回收器

5 Par New

特点:

  • 采用复制算法
  • 多线程的回收器
  • 属于加强版的PS,可以和CMS配合使用

6 CMS

清理过程:

  • 初始标记,找到根对象
  • 并发标记,找到与根对象连接的,进行标记
  • 重新标记,因为在并发标记的过程中可能造成新垃圾需重新标记
  • 并发清理,并发清理,可能造成浮动垃圾

特点:

  • 采用并发标记清除法
  • 空间碎片化(并发收集发生 Concurrent Mode Failure的时候使用Serial Old清理)
  • 最终会产生浮动垃圾
  • 不作为任何默认的垃圾回收器
  • STW严重到无法忍受的情况下使用CMS

相关参数:

-XX:+UseConcMarkSweepGC:激活CMS收集器,默认情况下使用ParNew + CMS + Serial Old的收集器组合进行内存回收,Serial Old作为CMS出现“Concurrent Mode Failure”失败后的后备收集器使用
-XX:CMSInitiatingOccupancyFraction={x}:在老年代的空间被占用{x}%时,调用CMS算法对老年代进行垃圾回收
-XX:CMSFullGCsBeforeCompaction={x}:在进行了{x}次CMS算法之后,对老年代进行一次compaction
-XX:ParallelCMSThreads={x}:设置CMS算法中并行线程的数量为{x}
-XX:+ExplicitGCInvokesConcurrent:用户程序中可能出现利用System.gc()触发系统Full GC(将会stop-the-world),利用这个参数可以指定System.gc()直接调用CMS算法做GC。
-XX:+DisableExplicitGC:该参数直接让JVM忽略用户程序中的System.gc()

问题:

  1. 空间碎片化

    -XX:+UseCMSCompactAtFullCollection
    -XX:CMSFullGCsBeforeCompaction 默认为0 指的是经过多少次FGC才进行压缩

  2. 浮动垃圾

    Concurrent Mode Failure
    产生:if the concurrent collector is unable to finish reclaiming the unreachable objects before the tenured generation fills up, or if an allocation cannot be satisfiedwith the available free space blocks in the tenured generation, then theapplication is paused and the collection is completed with all the applicationthreads stopped
    解决方案:降低触发CMS的阈值
    PromotionFailed
    解决方案类似,保持老年代有足够的空间
    –XX:CMSInitiatingOccupancyFraction 92% 可以降低这个值,让CMS保持老年代足够的空间

7 常见垃圾回收器组合参数设定:(1.8)

- -XX:+UseSerialGC = Serial + Serial Old
- -XX:+UseParNewGC = ParNew + SerialOld
- -XX:+UseConcurrentMarkSweepGC = ParNew + CMS + Serial Old
- -XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 
- -XX:+UseG1GC = G1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值