首页 > 从jvm到代理模式?你知道垃圾回收器吗?
头像
Evan_Wang🌴🌴
编辑于 2021-04-21 20:28
+ 关注

从jvm到代理模式?你知道垃圾回收器吗?

就是说Java代码一般来说要通过Java c。变成字节码文件,就是点class文件,然后再经过解释执行。这样花费的时间就是第一条路径。

第二条路径就是字节码文件,通过j it即时编译器变成二进制文件,这种二进制文件是与机器电脑的机型相关的,然后在平台上运行。

这个二进制文件会存在,个方法区里面。

这样的话。与机器相关的二进制文件执行起来,就比字解码文件本身的解释执行更快

既然jit这么好,为什么不直接全部代码由jit编译呢?

就是jit虽然快,但是只有在编译后才快。
图片说明

jit要两个过程是:编译+执行
翻译字节码是:解释执行

1、

编译只需要一次,永久保存二进制(编译后的文件)所以 jit第二编译后执行时间<解释执行。

但如果没有编译,jit编译时间+jit执行时间> 直接解释执行。

2、

编译在执行,持续在刚开始的时候就会卡。

去掉翻译字节码,直接由jit编译执行,这个会导致程序刚开始卡在编译这个用点时间,然后再执行,反馈给用户层的感受是卡一点

综上所述,

jit编译器就是在编译程序的代码段的时候,比如一些for循环,里面需要重复执行的代码,用jit编译成机器指令,放到方法区,然后就不用每次都经过解释器编译执行,提高了虚拟机的性能。

java才叫做解释编译型语言,可以让他在不同平台执行。

提供翻译与平台无关的字节码来执行的时候,体现这个特点,但jit就无关了。

如果走jit,编译后的二进制文件执行起来虽然快,但是这些jit“编译后的二进制文件”是与平台相关的,window的有window的格式,linux有linux格式。
图片说明

拓展这个代理模式,叫代理模式,

JDK Proxy 和 CGLib 是两种实现代码模式的方式,JDK Proxy 是spring默认支持的,简单理解他就是jdk自带的,在原本的代码里面做增强。

JDK Proxy这个例子太多。

我主要来讲CGLib ,动态代理也可以通过 CGLib 来实现,而 CGLib 是基于 ASM(一个 Java 字节码操作框架)而非反射实现的。
图片说明

这就回答了一个面试题,动态代理一定和反射有关系吗?不是的,JDK Proxy确实就是和反射挂钩,CGlib就不是。

我们举个例子。

Lombok

它属于 Java 的一个热门工具类,使用它可以有效的解决代码工程中那些繁琐又重复的代码,如 Setter、Getter、toString、equals 和 hashCode 等等,向这种方法都可以使用 Lombok 注解来完成。

例如,我们使用比较多的 Setter 和 Getter 方法,在没有使用 Lombok 之前,代码是这样的:

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

}

在使用 Lombok 之后,代码是这样的:

public class Person {

    private Integer id;

    private String name;

}

可以看出 Lombok 让代码简单和优雅

可以看出 Lombok 让代码简单和优雅

他就是用的CGlib

图片说明

从流程图中可以看出,在编译期阶段,当 Java 源码被抽象成语法树(AST)之后,Lombok 会根据自己的注解处理器动态修改 AST,增加新的代码(节点),在这一切执行之后就生成了最终的字节码(.class)文件,这就是 Lombok 的执行原理。

(AST设计编译原理,这里不谈,我们主要了解动态代理)

知道CMS吗?CMS的垃圾回收过程?哪个阶段是需要STW的?用的什么垃圾回收算法
提前了解回收算法,年轻代的复杂算法 老年代的标志-清除和标记-整理算法。

图片说明

注意:如果两个收集器之间存在连线,就说明它们可以搭配使用

1、

我们从蓝色和红色的开始

Serial 翻译过来就是连续,单线程回收

其次是红色 par就是parallel,并行回收

我们说下这两个的共同点和区别

共同点:

他们用的回收算法是类似的,
年轻代用:复制算法 ,
老年代:标志-清除和标记-整理算法。

他们都是简单而高效的回首,比如serial的这种垃圾回收器,它就单线程,他都只干自己的事情,可以很高效的进行回收,不会被他打扰

不同:

ParNew收集器其实就是Serial收集器的多线程版本。

多个cpu,工作更快

2、

图片说明
打红圈的这个par其实全称叫:Parallel Scavenge。

这时候你可能会有一个问题,par的新生代为什么有两个呢?

Parallel Scavenge和ParNew比较

共同点

和ParNew收集器一样,该收集器是在新生代的,也是并行的,也是采用 复制算法。

区别是:比起parnew,他更关注stw

面试题中的stw,这里说parallel scavenge也关注stw 那什么是stw?

stw 其实就是:stop the word,停止工作。

我们知道,虚拟机进行垃圾回收,其实也是会消耗cpu, 而且我们虚拟机的任务,比如我们代码里面在执行的某个循环,也消耗着cpu。

如果这个时候进行垃圾回收,那么有可能就需要把我们代码的for循环停止。然后进行垃圾回收完再继续执行。

那Parallel Scavenge是如何关注stw呢?

stw越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验;
而高吞吐量则可以高效率地利用CPU时间,尽快完成程序的运算任务

吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。
假如虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。

简单来说 ,他关注stw的方法,就是,注重在短时间内完成垃圾回收的任务(高吞吐)

4、

接下来,说说cms和g1,他俩就更牛逼了,可能在垃圾回收的期间 ,让用户线程与垃圾回收的任务共同执行。

他俩更关注stw,比如cms的垃圾回收过程是这样:

初始标记(CMS initial mark):需要“STW”,仅仅只是标记一下GC Roots能直接关联到的对象,速度很快;
并发标记(CMS concurrent mark):可以并发操作,主要是进行GC ROOT Tracing,有点慢,需要占用很多CPU资源
重新标记(CMS remark):需要“STW”,主要是针对并发标记期间重新进入到老年代的数据,这个阶段比初始标记时间长,但是远比并发标记短
并发清除(CMS concurrent sweep):就是清除数据,由于采用的是标记清除的算法,所以会产生一些碎片

四个过程,其实你会 好像只有并发标记过程,不用stw 也没快多少呀?

初始标记。并发标记,重新标记和清理这四个过程中。并发标记花费了时间其实是最长的,如果能在这个时间和,让用户线程也可以一起跑的话,可以很大提升效率。

顺便说一下cms用了什么算法,年轻代是使用了复制算法,而老年代是使用了标记清除算法,注意是标记清除,不是标记整理

全部评论

(0) 回帖
加载中...
话题 回帖

近期热帖

近期精华帖

热门推荐