快速认识JVM,深入掌握类加载器、JVM内存空间、JVM垃圾回收机制和双亲委派机制。

什么是JVM

        JVM(Java Virtual Mchine)java虚拟机,主要作用就是将Java字节码文件解释为能被各种操作系统理解的机器码

JVM的三大功能

        1.解释和运行:将字节码文件翻译为能被各种操作系统理解的机器码。

        2.内存分配:给对象及其方法分配内存,管理对象。

        3.即时编译(JIT):将热点代码编译为字节码放到内存中,提高效率。

类加载器ClassLoad

类的生命周期

类的加载阶段:

        将类的信息(硬盘、网络、反射)以二进制的形式加载到内存中。

 注意:具体放在InstanceKlass(c语言编写)中,但因为Java程序不便直接操作c语言程序,所以使用Java.lang.Class进行映射。通过操作Java.lang.Class来控制InstanceKlass。

类的连接阶段:

        连接阶段分为:验证、准备、解析。主要作用是验证Java代码是否符合规范、静态变量赋初始值(并不是直接赋原本变量值,而是赋0、1这种初值。final修饰变量在此阶段赋值)、将符号引用转变为内存地址值。

类的初始化阶段:

        初始化阶段主要是给静态变量赋真值、执行静态方法(final修饰的静态变量在连接节段的准备状态中赋值)。

        是否触发初始化,访问静态变量就会初始化。记住两个特例:final修饰的静态变量(final修饰静态变量赋值不为常量除外)、创建数组的类不会初始化。

触发初始化的情况:

  1. 使用Class.forName(),反射加载类
  2. 访问静态变量,访问final修饰的静态变量除外   
  3. new对象
  4. 访问final修饰的静态变量右边不是常量,会初始化(特殊情况)

不触发初始化的情况:

  1. 无静态代码块或无静态变量赋值语句
  2. 有静态变量,但是没有赋值
  3. 使用final关键字修饰的静态变量(final修饰的静态变量右边不是常量除外
  4. 创建数组的类,类本身不会初始化(特殊情况

类加载器

双亲委派机制(重点)

什么是双亲委派机制?

        加载类时,向父类寻找是否加载过该类,如果加载过类直接返回加载过的类,避免重复加载。寻找到启动类加载器后,从启动类加载器向下加载该类,保证加载类时的优先级顺序。

        Application的父类是Extension,Extension加载器的父类是BootStrap。

双亲委派机制的优点:

        1.避免恶意修改JDK的核心类库

        2.避免类被重复加载

如何打破双亲委派机制

为什么要打破双亲委派机制?

        双亲委派机制中类加载都是由Application、Extension、BootStrap加载,这样做不够灵活。例如在高度模块化的组件中,每个模块有自己的类加载器,操作自己的类加载器进行热操作,不去影响其他模块,这样操作更灵活。

如何打破双亲委派机制?

注意:

1.如果想实现自定义的类加载器,但是不想打破双亲委派机制,可以重写findClass方法。

2.类加载器和全限定类名相同,在Java中才会被认为是一个类。(类加载器不同,类名相同不是一个类)

重写ClassLoad类中loadClass()方法

双亲委派机制的核心逻辑,只要我们将这段代码重写就可以打破双亲委派机制

protected Class<?> loadClass(String name, boolean resolve)

 synchronized (getClassLoadingLock(name)) {

 Class<?> c = findLoadedClass(name);

    if (c == null) {
     if (parent != null) {
       c = parent.loadClass(name, false); //当前类加载器没有加载到类,就去父类寻找
      } else {
        c = findBootstrapClassOrNull(name);
         }
       }

JVM内存区域(重点)

JVM内存区域,各空间详解

线程不共享区

程序计数器:程序计数器记录当前线程字节码执行位置。作用是,在线程切换后该线程可以继续执行之前因线程切换而未完成的任务。

栈(当方法递归执行时会造成内存泄漏:通过(先进后出)来记录方法栈帧。方法栈帧包括局部变量表(存放局部变量)、操作数栈(存放临时数据)、帧数据(变量内存地址/动态链接、方法出口、异常表)。

本地方法栈:记录本地方法的方法栈帧。

线程共享区

(创建过多对象时会造成内存泄漏):存储对象、数据、集合。(重点是堆的垃圾回收)

方法区:储存类信息运行时常量池(放置在元空间中)、字符常量池(堆内存)。

JVM垃圾回收(重点)

如何判断可以垃圾回收的内存区域

引用计数法:给对象添加计数器,统计对象引用次数,如果为0表示没有引用该对象可以回收。存在的问题是,两个对象相互引用就无法回收。

可达性分析法(JVM采用方案):将对象分为两类,GCroot对象普通对象;如果普通对象的引用路线中有GCroot对象,就不会被回收。

GCroot对象包括:

  1. 线程对象
  2. java.lang,Class对象
  3. 监视器对象,,用来保存同步锁synchronized关键字持有的对象
  4. 本地方法栈中的全局变量

JVM垃圾回收算法

标记清除算法:标记不可回收空间,删除其他对象所占空间。

优点,实现简单;缺点,产生内存碎片

复制算法:将内存空间分为From,To两片空间。每次GC时会将不可回收对象放到To空间中,然后将To改为From(From改名为To,确保From永远存储不可回收对象)。

优点,解决内存碎片;缺点,空间利用效率低(只能利用一半内存)

标记整理算法:标记不可回收空间,并将这些空间转移到同一端,删除其他对象内存空间。

优点,解决内存碎片;缺点,需要执行多次空间转移算法时间利用率低

分代GC(重点)

分代GC中堆空间内存图

分代GC过程中对象经历的全过程(这是小编呕心沥血画的示意图,友友们觉着不错快点赞吧!)

G1垃圾回收器(重点)

G1垃圾回收器的特点:

  1. 将内存区域划分为Region,区域不连续而是独立的小块。     
  2.   支持多核CPU并发进行垃圾回收。
  3. 允许自主设置最大停止时间(G1通过判断Eden、Survivor区回收时间进行预估)

G1垃圾回收算法:

G1判断内存空间占年轻代60%,触发youngGC,回收年轻代内存,采用复制算法。

G1判断内存空间占总堆的45%,触发MixedGc,回收年轻代+老年代内存,采用复制算法。

G1判断内存空间占满,触发fullGC,回收年轻代+老年代内存,采用标记整理法。

并发垃圾回收过程

第一步:初始标记GCroot对象,阻塞执行。

第二步:标记GC存活对象并发执行。

第三步:最终标记的是标记GC存活对象并发过程中所修改的对象,不去管理新创建或者不再关联的对象,阻塞执行

第四步:并发清除垃圾对象并发执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值