JVM知识点梳理

什么是JVM?

        JVM是java虚拟机的缩写 ,也是java程式可以实现跨平台的关键。

JVM部分需要知道什么东西?

        JVM的结构和功能、参数配置、GC回收机制、GC回收器极其优缺点、类加载流程、双亲委派。

JVM结构(栈,程序计数器,方法区,栈)

从Java源码开始,JVM需要把源码转化为字节码,每个线程(包括主线程)都会产生一个虚拟机栈,里面会存储引用变量以及参数信息。程序计数器记录每个线程中执行的位置,当它遇到没见过的类时候,就会跑去对该类进行加载,将类的方法名,成员变量,注解等信息存储到方法区中。当该类被使用,new出对象,则将new的对象放到堆中。由此构建出JVM的结构,其中,程序计数器和栈是每个线程私有的,即多个线程时就会有多个对应的程序计数器和栈。而方法区和堆是共享且唯一的。

堆和栈的区别:
栈是运行时单位,每个线程私有,调用时入栈,返回结果时出栈,因此代表着逻辑,内含基本数据类型和堆中对象引用,所在区域连续,没有碎片;堆是存储单位,可被多个栈共享(包括成员中基本数据类型、引用和引用对象),代表着数据,所在区域不连续,会有碎片。
1 、功能不同
栈内存用来存储局部变量和方法调用,而堆内存用来存储 Java 中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。
2 、共享性不同
栈内存是线程私有的。 堆内存是所有线程共有的。
3 、异常错误不同
如果栈内存或者堆内存不足都会抛出异常。 栈空间不足: java.lang.StackOverFlowError 。 堆空间不足:java.lang.OutOfMemoryError
4 、空间大小
栈的空间大小远远小于堆的。

图中还包括解释器和即时编译器,解释器的作用是把字节码解释称CPU能识别的机器码,但是它是一条一条的解释,当有循环时,它会把循环中的内容一遍一遍的解释,故此会影响效率。此时即时编译器就发挥了它的作用,它把这些循环重复多次的语句存储,避免解释器反复解释。

JVM参数配置部分用一张图来解释:

 

GC回收

GC回收是指对内存中不再使用的对象进行清除的操作,把它们的资源释放出来。

GC回收原理是通过可达性算法和三色标记法配合,根据算法找到根对象,然后沿着根对象找与之相关的对象,使用黑灰白三色标记,将已经标记的表示为黑色,正在标记的表示为灰色,未标记的表示为白色。最终检查完后,将所有白色的进行清除。

GC回收机制有三种方法:

  • 标记清除法
  • 标记整理法
  • 标记复制法

由上述解释可知,所谓标记,是将正在使用的对象进行标记,标记清除法的意思就是将未标记的进行清除,它的优点是快速,缺点就是,会形成内存碎片,因为没发保证正在使用的都是连续的。而标记整理法,是在标记清除法上加了一个整理的步骤,将不连续的区域整理成连续的。因此它解决了标记清除法产生内存碎片的问题,但是它的缺点就是会导致速度不如前者。于是产生了第三种标记复制法,它会产生两个内存区,“from”和“to”,它会把所有标记的内容复制到to区上,复制完后,就把原本的区域全部清除掉,清除完之后,会把from区和to区调换位置,后续操作依次。它解决了标记清除法和标记整理法的缺点,但是它的缺点是需要多一块区域,会比另外两个方法多占用内存资源。

标记清除法,现在的GC垃圾回收器都已经没有使用了。

标记整理法,常用于老年代。

标记复制法,常用于新生代。

上述提到两个新名词,老年代和新生代,这两个区都在堆中。其中新生代又划分为eden区和Survivor区(默认eden区和Survivor区大小比例为八比一,Survivor区包含两个区域,一个叫“from”一个叫“to”),所有新new的对象都会先在eden区创建,当eden区堆积满了之后,做垃圾回收,会把还存在的对象放入Survivor,当Survivor经过多次垃圾回收,依旧存在的对象就会进入老年代(默认操作15次)。因为新生代朝生暮死,大多数生命周期短,因此可以减少复制使用到的空间,故而标记复制法适用于新生代。又因为老年代默认为生命周期长,而且标记整理法中整理部分比较耗费时间,但是老年代的垃圾回收频率会低很多,故而老年代使用的是比较耗费时间的标记整理法。

GC按回收区域可以分成两大类:部分收集(Partial GC)和整体收集(Full GC)。

因为垃圾回收是会需要释放时间的,因为会导致程序出现STW(stop the world)。

部分收集相对比较快速,整体收集就相对来说需要耗费比较大的时间成本。因此尽可能希望CPU做部分收集。

部分收集:

        新生代回收(Minor GC)

        老年代回收(Major GC)

整体收集:

        同时清理新生代和老年代(Full GC

垃圾回收器包括:Parallel GC、Concurrent Mark Sweep GC、G1 GC等。

Paarllel GC:注重的是吞吐量。

Concurrent Mark Sweep GC:注重响应速度。

G1 GC:兼容吞吐量和响应速度。

垃圾回收的触发条件:
1.新生代(Minor GC)触发条件
        伊甸园空间不足,就会进行Minor GC回收新生代

2.老年代(Full GC)触发条件

  •         老年代空间不足
  •         元空间不足
  •         要晋升老年代的对象所占用的空间大于老年代的剩余空间。
  •         显式调用System.gc()
  •         建议垃圾回收器执行垃圾回收
  •         -XX: +DisableExplicitGC 参数,忽略掉System.gc()的调用

类加载

类加载流程分为三步:

1.加载

  1. 将字节码加载到方法区中,并产生.class对象
  2. 如果该class有父类,且父类未加载,优先加载父类
  3. 类加载为懒惰加载机制,即第一次使用时才启动加载

2.链接

  1. 验证阶段,验证Class是否符合代码规范,合法性安全性检查
  2. 准备阶段,为static静态元素分配空间,设置默认值
  3. 解析阶段,将常量池的符号引用解析为直接引用

3.初始化

  1. 执行静态代码和非final静态代码块的赋值
  2. 依旧为懒惰机制

上述类加载流程中的加载步骤提到,当加载的class有父类时,会优先加载父类,那么此时会涉及到一个问题,那就是,父类的加载由谁来执行。这就涉及到了双亲委派机制。

所谓双亲委派,就是优先委派上级加载器进行加载,如果上级加载器找的到该类,那么上级加载器加载后,该类对下级加载器也是可见的,只有当上级加载器找不到该类时,下级加载器才有资格进行加载。

 

 双亲委派机制的优点:

        1.避免了类的重复加载(因为一般情况只会由最顶层来加载)

        2.保护了程序的安全性,防止核心的API被修改

 

上述不够完整,持续维护中……

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值