2020-08-01- 第九周学习总结

用户头像
路易斯李李李
关注
发布于: 2020 年 08 月 03 日

一、JVM组成架构

Java是一种跨平台语言,JVM屏蔽了底层系统的不同,为Java字节码文件构造了一个统一的运行环境。

JVM由三部分组成:类加载器运行期数据区执行引擎。其中运行期数据区分为四个部分:方法区,堆区,Java栈和程序计数寄存器。方法区和堆区是所有线程共享的数据区,而Java栈和程序计数寄存器则是线程独有的,每个线程均有一份。

类加载器负责将类文件加载到运行期数据区,运行时开启线程,给方法创建栈帧,并压入Java栈中。执行时由于类文件存储的是字节码指令,不能直接由操作系统解析执行,必须通过执行引擎对字节码指令进行解析成本地指令,最终在本地操作系统上进行执行。

二、字节码执行流程

将一个字节码指令交给执行引擎,首先查看该字节码是否是已经编译过的。如果是已经编译的,则直接执行编译后的机器码。如果是没有编译过的,需要将方法调用计数器加1,也就是看这个方法执行过多少次,每执行一次就加1。之后看方法调用计数器是否超过阈值。如果超过了阈值则说明这条是一个热点指令,则对此字节码进行编译,经编译器和后台执行编译,最终将其生成机器码。如果没有超过阈值,则对其进行解释执行。

三、类加载器

(1)双亲委托机制

低层次的当前类加载器,不能覆盖高层次类加载器已经加载的类。如果低层次的类加载器想加载一个未知类,需要上级类加载器确认,只有当上级类加载器确认没有加载过这个类,才会允许当前类加载器加载这个未知类。

双亲委托,其中双亲应该是指BootStrapClassLoader和ExtClassLoader两个类加载器,这两个分别是AppClassLoader的祖父和父亲,所以双亲应该是值AppClassLoader的祖父和父亲。

当AppClassLoader加载一个类的时候,如果没有加载过则需要委托给父亲加载,父亲查看是否加载过,如果没有则扔给祖父,如果祖父没有则让父亲去加载,父亲则又让AppClassLoader去加载。

(2)自定义类加载器

主要场景有:

隔离加载类:同一个JVM中不同组件加载同一个类的不同版本。

扩展加载源:从网络、数据库等处加载字节码

字节码加密:加载自定义的加密字节码,在ClassLoader中解密。

四、运行期数据区

每个JVM实例唯一对应一个,应用程序在运行中所创建的所有类实例或数组都存放在这个堆里,并由应用所有的线程共享。JVM为每个新创建的线程都分配一个堆。也就是说,对于一个java程序来说,它的运行就是通过对堆栈的操作来完成的。

Java中所有的对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的引用而已。

方法区主要存放从磁盘加载进来的类字节码,而在程序运行过程中创建的类实例则存放在堆里。程序运行的时候,实际上是以线程为单位运行的,当JVM进入启动类的main方法的时候,就会为应用程序创建一个主线程,main方法里的代码就会被这个主线程执行,每个线程有自己的java栈,栈里存放着方法运行期的局部变量。而当前线程执行到哪一行字节码指令,这个信息则被存放在程序计数寄存器中。



方法的静态变量存放在方法区内,静态变量new出来的实例则存放在堆中。没有出口的递归函数调用,肯定会导致栈溢出,这是因为java线程栈均有自己的空间上限。

五、垃圾回收

(1)回收方法

进行完标记后,JVM就会对垃圾对象占用的内存进行回收,回收主要有三种方法

  • 清理:将垃圾对象占用的内存清理掉,其实JVM并不会真的将这些垃圾内存进行清理,而是将这些垃圾对象占用的内存空间标记为空闲,记录在一个空闲列表里,当应用程序需要创建新对象的时候,就从空闲列表中找一段空闲内存分配给这个新对象。

  • 压缩:从堆空间的头部开始,将存活的对象拷贝放在一段连续的内存空间中,那么其余的空间就是连续的空闲空间。

  • 复制:将堆空间分成两部分,只在其中一部分创建对象,当这个部分空间用完的时候,将标记过的可用对象复制到另一个空间中。

(2)垃圾回收算法

串行回收器是指使用单线程进行垃圾回收的回收器。每次回收时,串行回收器只有一个工作线程,对于并发能力较弱的计算机来说,串行回收器的专注性和独占性往往有更好的性能表现。在进行垃圾回收时,JAVA应用程序所有线程均要暂停,等待垃圾回收完成,此时便是Stop-The-World。

并行回收器是将串行回收器给多线程化,算法策略同串行回收器。由于并行回收器使用多线程进行垃圾回收,因此在并发能力强的CPU上,它产生的STW时间要比串行回收器短。

并发回收器CMS(Concurrent Mark-Sweep)首先初始化标记,需要STW,从垃圾回收的根对象开始,扫描并标记所有与跟对象关联的对象;接着是并发标记,在上一步的基础上继续向下追溯标记,这个阶段应用程序的线程和并发标记的线程并发执行,不会产生STW现象;然后是重标记阶段,需要STW,从根对象开始向下追溯,并重新标记上个阶段产生的关联对象;最后是并发清理阶段,清理垃圾对象,与应用线程并发执行。

G1回收器将堆内存划分为固定大小的多个区域,每个Region区域在JVM启动时就被划分好了,通常生成2000个左右的heap区,每个区域均有自己的新生代和老年代。与CMS回收器类似,G1回收器也分为初始标记、并发标记、最终标记和筛选回收几个阶段。基于Region区块机制,G1可对回收价值和成本进行排序回收,根据GC期望时间进行回收。



用户头像

路易斯李李李

关注

还未添加个人签名 2020.05.11 加入

还未添加个人简介

评论

发布
暂无评论
2020-08-01-第九周学习总结