目次
一.什么是JVM
1.先容
2.为什么Java是跨平台的?
3.为什么说Java是“编译与表明并存”的语言?
1.编译型语言
2.表明型语言
二.类的生命周期
1.概述
2.加载阶段
3.毗连阶段
1.验证
2.准备
3.解析
4.初始化阶段
5.口试题
1.类加载是懒惰的
2.final修饰根本范例和引用范例
3.符号引用变为直接引用
二.类加载器
1.类加载器的分类
2.启动类加载器
3.扩展类加载器和应用类加载器
1.扩展类加载器
2.应用程序类加载器
4.双亲委派机制
1.流程
2.标题
3.总结
5.冲破双亲委派机制
1.自界说类加载器
2.利用线程上下文的类加载器冲破双亲委派机制
1.标题1:Drivermanager怎么找到这个要加载的驱动呢?
2.标题2:Drivermanager是怎样通过SPI机制加载这个类的呢?
3.这种方式到底有没有冲破双亲委派机制?
三.运行时数据区
1.目标
2.程序计数器
1.先容
2.作用
3.标题
3.假造机栈
1.简朴先容
2.局部变量表
总结
3.操纵数栈和帧数据
1.动态链接
2.方法出口
3.非常表
4.栈内存溢出
4.堆
1.对象创建过程
2.new对象会发生辩说吗?
2.对象在堆上是怎样存储的?
1.CPU缓存行知识
2.对象的存储
3.访问对象的方式
5.方法区
1.方法区先容
2.类的元信息
3.运行时常量池和常量池
4.字符串常量池(StringTable)
1.标题
6.直接内存(属于操纵体系内存)
JIT即时编译器
1.先容
2.优化本事——方法内联
3.优化本事——逃逸分析
五.垃圾回收
1.方法区的回收
2.堆回收
编辑
1.引用计数法
2.****可达性分析***(GC Root)
3.五种对象引用
1.强引用
1.软引用
3.弱引用
4.虚闭幕器引用
4.垃圾回收算法
1.算法的评价尺度
1.吞吐量
2.最大停息时间
3.堆利用服从
2.标志扫除算法
3.复制算法
4.标志整理算法
5.分代GC
5.垃圾回收器
1.年轻代——Serial垃圾回收器与老年代——SerialOld垃圾回收器
2.年轻代——ParNew垃圾回收器与老年代——CMS垃圾回收器
缺点:
3.Parallel Scavenge和parallel Old垃圾回收器
4.G1垃圾回收器
1.年轻代回收——YoungGC
跨代引用的标题(老年代引用了年轻代)
2.混淆回收(Mixed GC)
1.初始标志(三色标志法)
2.并发标志阶段
3.终极标志阶段
4.转移(先复制再删除,看起来像转移)
3.对比CMS
一.什么是JVM
1.先容
JVM是Java假造机,程序运行之前,需要先通过编译器将 Java 源代码文件编译成 Java 字节码文件。程序运行时,JVM 会对字节码文件举行逐行表明,翻译成呆板码指令,并交给对应的操纵体系去实行。这时就引出了以下的几个标题:
2.为什么Java是跨平台的?
在java代码被编译成字节码后,JVM会将加载字节码,将字节码翻译成对应操纵体系的呆板码然后实行。换句话说,java在一次编译后,可以在多个操纵体系上运行。也就实现了跨平台的效果。
3.为什么说Java是“编译与表明并存”的语言?
起重要表明一下什么是编译性语言,什么是表明型语言。
1.编译型语言
编译型语言是指编译器针对特定的操纵体系,将源代码一次性翻译成可被该平台实行的呆板码。
比如说:找个翻译,等翻译将小说全部都翻译成汉语,一次性读完。
2.表明型语言
表明型语言是指表明器对源代码举行逐行表明,表明成特定平台的呆板码并实行。
比如说:找个翻译,翻译一段我读一段,逐步把书读完。
而Java则是需要先将 Java 源代码文件编译字节码文件,再表明实行。
二.类的生命周期
1.概述
2.加载阶段
3.毗连阶段
1.验证
2.准备
特别情况:
3.解析
4.初始化阶段
为静态变量赋值
有静态变量的声明,但是没有赋值语句,不会初始化。
有final修饰,也不会初始化
有静态变量的声明,也有赋值语句,则会初始化。
public static int i =10;
5.口试题
1.类加载是懒惰的
2.final修饰根本范例和引用范例
都是直接从别的类直接复制过来,如果数字小,就是在栈中获取,如果数字较大,就是在这个类的常量池中获取。
3.符号引用变为直接引用
A还没有加载的时间,就是符号引用,由于TestFinal这个类根本不知道A在哪
加载后
那么JVM到底是怎么将编译好的字节码加载到假造机中然后实行的呢?接着往下看吧。
二.类加载器
1.类加载器的分类
2.启动类加载器
3.扩展类加载器和应用类加载器
1.扩展类加载器
2.应用程序类加载器
应用程序类加载器重要加载我们写的一些类(编译出来的)以及maven中依靠的第三方的一些类。
但是应用程序类加载器还加载了扩展类加载器和启动类加载器加载的一些内容,那如许不会辩说吗?答案是不会,至于为什么会在下一节的双亲委派机制中详细讲授!
4.双亲委派机制
假造机中有多个类,双亲委派机制重要就是为了办理一个类到底由谁来加载的标题。
1.流程
向上查找,从底部不停向上查找,看有没有哪个类加载过,加载过就返回
向下加载,看本身能不能加载,能加载就加载,不能加载就委派给下面的加载,知道可以加载。向下委派加载起到了加载优先级的作用。
这时如果B再来加载,就是向上查找,发现已经加载过了,就直接返回。如许就制止了类被重复加载。
另一个小案例:
2.标题
3.总结
5.冲破双亲委派机制
为什么要冲破双亲委派机制?怎么冲破双亲委派机制?
1.自界说类加载器
loadclass:这个方法就是实现双亲委派的逻辑,它会调用findclass方法
findclass:通过类的全限定名,找到要加载类的二进制数据,然后调用defineclass方法将二 进制的数据传进去
defineclass:在堆和方法区中创建包罗类信息的对象。(调用底层的假造机方法)加载阶段 就完成了
resolveclass:实行类生命周期中的毗连阶段。可以在loadclass方法中设置为false
以是我们可以重写loadclass方法
看不打到双亲委派的踪影了,根据类的全限定名找到对应的字节码文件加载到内存中酿成一个二进制数组。然后通过defineclass在堆和方法区天生对应的数据。
2.利用线程上下文的类加载器冲破双亲委派机制
JDBC在java中用来操纵数据库,差异的数据库有它差异的实现方式,它得进步它的泛用性,将来对接任何的数据库都会变的很容易。JDBC中利用了DriverManager这个类来管理新项目中引入的差异数据库驱动,比如我们要利用mysql这个数据库,它就会负责将mysql的驱动jar包加载进来,后续就可以举行毗连操纵等等。但要加载这个驱动就出现了一些标题。请往下看。
1.标题1:Drivermanager怎么找到这个要加载的驱动呢?
答:它利用了SPI机制,它是一种JDK内置的服务发现机制,如果说想要加载一个接口的实现类对象,就可以通过它快速的找到。
起首mysql驱动得把本身暴漏出去给Drivermanager看到,以是它得在一个固定的文件夹下,META-INF/service下,以接口的全限定名来命名这个文件,数据库驱动都会实现这个接口,实现了这个接口的,DM才会以为它是一个数据库驱动,文件内里写的就是这个接口的实现类的全限定名。下面是一个mysql驱动的实现类,它也实现了这个接口,而且在它的静态代码块中将本身注册到了Drivermanager中,只要这个类被加载并初始化,注册驱动的过程就直接完成了。
准备阶段完成后,SPI提供了一个ServiceLoader这个类,此中有一个load方法,只需要把接口名字传进去,拿到这个类的对象后,就可以通过迭代去找到这个实现类并加载这个类。
Drivermanager的代码
Drivermanager要调用getconnection方法,需要完成初始化操纵,在它的静态代码块中利用了loadInitialDrivers方法。
loadInitialDrivers方法里利用ServiceLoader通过迭代器拿到
2.标题2:Drivermanager是怎样通过SPI机制加载这个类的呢?
但Drivermanager是位于rt.jar中是由启动类加载器中加载的,而mysql驱动是由应用程序类加载器加载的。
在ServiceLoader的load方法中,通过拿到线程上下文的类加载器,也就是应用程序类加载器,从而加载驱动。
3.这种方式到底有没有冲破双亲委派机制?
我个人以为着实并没有冲破双亲委派机制,由于不管是Drivermanager的加载,照旧数据库驱动的加载,着实都是符合双亲委派的向上查找和向下加载的逻辑的。
三.运行时数据区
1.目标
2.程序计数器
1.先容
代码是需要表明器去实行的,表明器只需要去找程序计数器要这个地点,就知道要实行的字节码指令是什么了。
多线程的情况下,cpu来回切换。
2.作用
从上面这些我们就可以看出程序计数器有两个作用
1.来控制表明器来实行指令的序次
2.在多线程的情况下,cpu来回切换,程序计数器可以记载切换前实行到了哪一句指令,来举行后续的运行。
3.标题
3.假造机栈
1.简朴先容
2.局部变量表
- 局部变量在方法、构造方法、大概语句块被实行的时间创建,当它们实行完成后,将会被烧毁。
- 访问修饰符不能用于局部变量。
- 局部变量只在声明它的方法、构造方法大概语句块中可见。
- 局部变量是在栈上分配的。
- 局部变量没有默认值,以是局部变量被声明后,必须经过初始化,才可以利用。
总结
局部变量表在运行过程中存放所有的局部变量,以及方法的参数以及实例方法中的this对象。
3.操纵数栈和帧数据
1.动态链接
由于当前类的字节码访问了其他类耳洞属性大概方法,如getstatic,由于访问的是其他类的,以是在毗连阶段不会直接将符号引用变为直接引用。以是在实行这条字节码之前,需要生存一个符号引用到谁人类的运行时常量池的一个引用关系。在实行这条字节码时,就可以通过这个关系,找到谁人你需要的类以及这个类你需要的数据。
2.方法出口
3.非常表
finally的原理
4.栈内存溢出
4.堆
1.对象创建过程
当我们利用 new 关键字创建一个对象时,JVM 起首会检查 new 指令的参数是否能在常量池中定位到类的符号引用,然后检查这个符号引用代表的类是否已被加载、解析和初始化。如果没有,就先实行类加载。
如果已经加载,JVM 会为对象分配内存完成初始化,比如数值范例的成员变量初始值是 0,布尔范例是 false,对象范例是 null。
接下来会设置对象头,内里包罗了对象是哪个类的实例、对象的哈希码、对象的 GC 分代年龄等信息。
末了,JVM 会实行构造方法 <init> 完成赋值操纵,将成员变量赋值为预期的值,比如 int age = 18,如许一个对象就创建完成了。
2.new对象会发生辩说吗?
new 对象时,指针会向右移动一个对象大小的间隔,在多线程的情况下,如果一个线程 A 正在给字符串对象 s 分配内存,别的一个线程 B 同时为 ArrayList 对象 l 分配内存,两个线程就发生了抢占。
怎样办理这个标题呢?
为了办理堆内存分配的竞争标题,JVM 为每个线程生存了一小块内存空间,被称为 TLAB,也就是线程本地分配缓冲区,用于存放该线程分配的对象。当线程需要分配对象时,直接从 TLAB 中分配。只有当 TLAB 用尽或对象太大需要直接在堆中分配时,才会利用全局分配指针。
2.对象在堆上是怎样存储的?
1.CPU缓存行知识
2.对象的存储
内存对齐添补:
办理方法就是内存对齐
3.访问对象的方式
主流的方式有两种:句柄和直接指针。
两种方式的区别在于,句柄是通过一个中心的句柄表来定位对象的,而直接指针则是通过引用直接指向对象的内存地点。
长处是,对象被移动时只需要修改句柄表中的指针,而不需要修改对象引用本身。
在直接指针访问中,引用直接存储对象的内存地点;对象的实例数据和范例信息都存储在堆中固定的内存区域。
长处是访问速率更快,由于少了一次句柄的寻址操纵。缺点是如果对象在内存中移动,引用需要更新为新的地点。
HotSpot 假造机重要利用直接指针来举行对象访问。
5.方法区
1.方法区先容
2.类的元信息
3.运行时常量池和常量池
4.字符串常量池(StringTable)
1.标题
6.直接内存(属于操纵体系内存)
JIT即时编译器
1.先容
2.优化本事——方法内联
3.优化本事——逃逸分析
不会作为参数转达,而且不会return出去
五.垃圾回收
1.方法区的回收
2.堆回收
要举行对象的回收,我们得知道哪些对象可以被回收,详细是根据是否被引用来决定的。那有哪几种方法来确定哪些对象可以被回收了呢?以下有两种方法。
1.引用计数法
2.****可达性分析***(GC Root)
a.一些活动线程
线程内会涉及到一些方法的调用,在栈帧中就存在着一些方法参数,局部变量等
b.一些焦点类(由启动类加载器加载的一些类)
如Object,string等等 java.lang.class
c.被锁住的对象 synchronized(对象)
d.本地方法引用到的对象
3.五种对象引用
1.强引用
1.软引用


当软引用的对象被回收时,这个对象关联的软引用也应该被回收,但不能贸然的把这个软引用置空,由于谁人对象不愿定会回收,内存富足的话就不消回收了,那怎么办呢?

一个案例:

- //利用软引用缓存学生对象
- public class StudentCache {
- private static StudentCache cache = new StudentCache();
- private Map<Long, StudentRef> refs;
- private ReferenceQueue q;
- //对外暴露单例
- public static StudentCache getInstance(){
- return cache;
- }
- public StudentCache(){
- refs = new HashMap<>();
- q = new ReferenceQueue<>();
- }
- private class StudentRef extends SoftReference<Student>{
- private Long _key = null;
- public StudentRef(Student s,ReferenceQueue q){
- super(s,q);
- _key = s.getId();
- }
- }
- public void cacheStudent(Student s){
- cleanCache();
- StudentRef ref = new StudentRef(s, q);
- refs.put(s.id, ref);
- System.out.println(refs.size());
- }
- private void cleanCache() {
- StudentRef ref = null;
- while((ref =(StudentRef)q.poll()) != null){
- refs.remove(ref._key);
- }
- }
- public static void main(String[] args) {
- for (Long i = 0L; ; i++){
- StudentCache.getInstance().cacheStudent(new Student(i, String.valueOf(i)));
- }
- }
- static class Student {
- Long id;
- String name;
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Student(Long id, String name) {
- this.id = id;
- this.name = name;
- }
- public Student() {
- }
- }
- }
复制代码 3.弱引用
4.虚闭幕器引用
4.垃圾回收算法
1.算法的评价尺度
1.吞吐量
gc的时间越少,吞吐量太高
2.最大停息时间
3.堆利用服从
2.标志扫除算法
3.复制算法
4.标志整理算法
5.分代GC
1.分成两个代程序员可以机动调解年轻代和老年代的比例去适配差异的应用程序,怎样用户的访问量很多,如去访问订单数据,如果新生代设置的很小,大量的对象都会进入新生代,频繁触发minor GC,有些对象还会进入老年代,大概这些对象的生命周期比力短,不盼望它去占用老年代的位置,盼望它在新年代就被回收而不进入老年代。
2.接纳差异的回收算法,新生代接纳复制算法,不会出现内存碎片而且吞吐量较高。而老年代空间一样平常较大,就不会接纳复制算法,由于复制算法只能利用堆内存大的一半,以是利用标志扫除和整理算法,但会(扫除)产生内存碎片,(整理)停顿时间也较长。
3.只要新生代可以或许满意对象的分配,就可以只发生minor gc,而不会发生full gc,STW的时间就会变少。
焦点就是降低垃圾回收对我们体系的影响!
5.垃圾回收器
1.年轻代——Serial垃圾回收器与老年代——SerialOld垃圾回收器
串行
2.年轻代——ParNew垃圾回收器与老年代——CMS垃圾回收器
相应时间优先,停顿时间较短
缺点:
1.利用了标志扫除算法:会产生大量的内存碎片。导致无法分配稍微大一点的对象,触发full GC
2.由于在并发标志阶段,是和用户线程并发实行的,对象的引用大概出现变动,以是无法处理处罚在这个过程中产生的“浮动垃圾”。
3.对于大对象是会直接放到old区,如果old区无法分配对象了,就会退化为单线程回收老年代,full gc(1 3条是一个意思)
3.Parallel Scavenge和parallel Old垃圾回收器
吞吐量优先
4.G1垃圾回收器
1.年轻代回收——YoungGC
跨代引用的标题(老年代引用了年轻代)
由于young gc只标志的是eden和survivor区的对象,那如果有老年代的对象引用了年轻代的对象,如下图所示,这里的E对象不能被回收,但是并没有扫描old区的对象,就没有找到这个e对象,那怎么找到呢?
将A,B,C也要到场到GC root中
每个区域的卡表会映射到整个堆的空间
那怎样维护这个卡表,大概说修改卡表的数据呢?运用写屏蔽技能
2.混淆回收(Mixed GC)
1.初始标志(三色标志法)
只是标志了从GC root可直达的对象
2.并发标志阶段
三色标志法存在的标题:
由于并发标志阶段是和用户线程一起工作的,并没有触发STW。用户线程大概修改了对象的引用关系,就出现了错标的情况。
标志开始时,先天生一个快照,记载下当前所有的对象
3.终极标志阶段
4.转移(先复制再删除,看起来像转移)
Full GC
3.对比CMS
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|