JVM——运行时数据区、双亲委派模型、垃圾回收算法、垃圾收集器(2)

(5)初始化

2、双亲委派模型

(1)什么是双亲委派模型

(2)双亲委派模型的优点

(3)破坏双亲委派模型

四、垃圾回收(GC)

1、死亡对象判断算法

(1)引用计数算法

(2)可达性分析算法

2、垃圾回收算法

(1)标记清除算法(老年代回收算法)

(2)复制算法(新生代算法)

(3)标记整理算法(老年代算法)

(4)分代算法

3、垃圾收集器

(1)CMS收集器(Concurr Mark  Sweep)

(2)G1收集器(唯一一个全区域的垃圾回收器)

五、Java内存模型

1、主内存和工作内存

2、内存间交互操作

(1)八大原子性的字节码指令

(2)Java内存模型的三大特性


一、JVM简介

JVM意为Java虚拟机。虚拟机是指通过软件模拟的具有完整的硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。

常见的虚拟机:JVM、WMware、Virtual Box。

JVM和其他两个虚拟机的区别:

  • VMware等是通过软件模拟物理CPU的指令集,物理系统中会有很多的寄存器;
  • JVM则是通过软件模拟Java字节码的指令集,JVM只是保留了PC寄存器,其他的寄存器都进行了裁剪。

JDK、JRE、JVM的关联关系:

 JDK和JRE的目录下都存在java.exe,通过其来运行class字节码文件,启动的时候就会创建一个JVM。JDK默认的JVM是HotSpot VM。

二、运行时数据区

1、堆(heap)

程序中所有创建的对象(数组也是对象)都存放在堆中

  • 对象指的是等号右边的;
  • 变量指的是等号左边的。

注:jdk1.8,常量池(字符串常量池)也在堆中。

JVM参数设置:

  • -Xms最小堆内存;
  • -Xmx最大堆内存

堆里面分为两个区域(逻辑上):新生代老生代。新生代放新建的对象,经过一定GC次数之后仍然存活的对象以及创建的大对象会放入老生代。

垃圾回收的时候会将Eden中存活的对象放在一个未使用的Survivor中,并把当前正在使用的Eden和Survivor清理掉。

2、方法区

用来存放被虚拟机加载的类信息(class字节码,进行类加载,把类加载到方法区,保存类的代码数据,同时堆中会生成一个类对象)、常量、静态变量、即时编译器编译后的代码等

  • 永久代(JDK1.7):属于Java内存进程;
  • 元空间(JDK1.8):内存属于本地内存,不再受JVM最大内存的影响,与本地内存的大小有关。
  • javac:编译器(编译Java代码为字节码文件);
  • java:包含解释器(Java程序运行的时候,把class字节码文件翻译为机器码);
  • 即时编译器:运行时,将热点代码翻译为机器码,之后就不用再进行翻译。
3、Java虚拟机栈
  • Java虚拟机栈的生命周期和线程相同,
  • 每个方法执行的时候都会创建一个栈帧,进行入栈操作,方法返回时,出栈;包含局部变量表、操作栈、动态链表、方法返回地址。

Java虚拟机栈:

  • 局部变量表:**存放八大基本数据类型、变量(等号左边)。**局部变量表所需的空间在编译时分配。进入一个方法时,方法在帧内分配的局部变量空间是确定的,执行期间局部变量表的大小不会发生改变。
  • 操作栈:每个方法会生成一个先进后出的操作栈;
  • 动态链表:指向运行时常量池的方法引用;
  • 方法返回地址:PC寄存器的地址。
4、本地方法栈

**调用Java方法,就创建栈帧,**放在线程的Java虚拟机栈中;如果调用其他的函数,就是用本地方法栈。

5、程序计数器

记录当前线程执行的行号。

6、内存布局中的异常问题
  1. 内存溢出(OOM):指存放数据的大小超出该区域的内存大小。运行时数据区域中,除了程序计数器,都可能发生内存溢出。内存溢出会导致整个进程都挂掉;
  2. 内存泄漏:线程生命周期太长,始终引用一些不使用的数据(没法进行gc垃圾回收),随着使用时间越来越长,不适用的垃圾就越来越多,可用空间越来越少——可能导致OOM。(解决方法:直接重启)
  3. StackOverflow:如果栈中的栈帧数量超过jvm规定,就会出现该异常。(递归使用不恰当)

三、类加载

1、类加载过程

(1)加载

加载class字节码到Java进程的内存中,在堆中创建类对象。

(2)验证

验证class字节码的规范(是否符合jvm规范)。

(3)准备

正式为类中的变量(静态变量)分配内存并对类变量进行初始化:

  • static常量:赋值为初始值;
  • static变量:赋值为缺省值;(Integer缺省值为null,int为0)
(4)解析

把常量池中的符号引用替换为直接引用:

  • 符号引用:class文件(字节码)private static int x=123;此时进程还没有启动,无法表示变量x指向123(本质是指向内存地址),此时使用符号引用来表示这个指向关系;
  • 直接引用:进程运行起来,x直接指向123(内存地址);
  • 替换:把class文件常量池中的符号引用,替换为进程运行起来的运行时常量池中的直接引用。
(5)初始化

是类的初始化,不是对象初始化。初始化阶段,Java虚拟机真正开始执行类中编写的Java程序代码。初始化阶段就是执行类构造器方法的过程。

类对象的初始化:执行静态变量和静态代码块。

2、双亲委派模型

(1)什么是双亲委派模型

类加载的机制:双亲委派模型(jdk默认的类加载机制),其它机制(破坏双亲委派模型的其它机制)。

**类加载器:**包含四种,从上而下(上下关系,不是以extends继承来实现的,是逻辑上的上下关系):

  • BootStrap ClassLoader   启动类加载器(主要负责加载Java核心类库,即%JRE_HOME%\lib目录)
  • ExtClassLoader   扩展类加载器(主要负责加载目录%JRE_HOME%\lib\ext目录下的类)
  • AppClassLoader  系统/应用类加载器(加载当前应用的classpath目录下的类)
  • 自定义加载器

启动/扩展/应用这三类类加载器,只是加载jar目录下不同的jar包。

什么是双亲委派模型?

基于四种类加载器,按照从上到下的顺序,来加载类。类加载器收到类加载请求时,不会立即去自己加载,而是将这个请求向上传递,每一层都是如此,因此所有的加载请求最终应该在最顶层的启动类加载器中。因为类加载只执行一次,所以,上边找到,下边就不执行加载;上边没有找到,就交给下一级的加载。

(2)双亲委派模型的优点
  • 避免重复加载类:如A类和B类都有一个父类C,当A启动起来的时候就会加载C,则B类进行加载时就不需要重复加载C类。
  • 安全性:确保优先采用启动/扩展/应用类加载器来加载类。
    如果自定义一个类加载,加载自定义的java.long.Object类:
    【1】遵循双亲委派模型,就不会加载到自定义的Object,还是jre中的(安全);
    【2】不遵循双亲委派模型,就可以加载到自定义的Object类(不安全)。

【注】在jdk中,自定义类加载器时,进行了安全校验:加载类,如果类的全限定名以java./javax.开头的包,报错。

(3)破坏双亲委派模型

遵循双亲委派机制的类加载,某些场景下,可能无法实现知道需要加载的类名(jdbc中,jdk是无法知道数据库驱动类的类名)。

解决方案:破坏双亲委派机制。

常用的方案:SPI机制(jdk提供的一个ServiceLoader.load,约定了从jar包下/META-INF/services/文件名  中进行加载)

四、垃圾回收(GC)

  • Java语言,不用自己分配内存,也不用自己回收内存(jvm中,实现了垃圾回收机制,自动回收)。
  • 垃圾回收区域:堆(回收的主要区域)、方法区(保存类信息,静态变量,很少回收);

1、死亡对象判断算法

(1)引用计数算法

给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器-1;任何时刻计数器为零的对象不能再被使用,即对象已死。**但jvm中没有选用引用计数器来管理内存:引用计数器无法解决对象的循环引用问题。**如下:

//此时instance的引用计数器会陷入死循环
Test test1 = new Test();
Test test2 = new Test();
test1.instance = test2;
test2.instance = test1;
(2)可达性分析算法

通过一系列称为“GC Roots”的对象作为起始点,从这些节点往下搜索,搜索走过的路径称为“引用链”,当一个对象到GC Roots没有引用链相连时,证明是“不可达的”

引用的分类(强度依次递减):

  • 强引用:只要引用还在,就不会被回收;
  • 软引用(SoftReference):系统要发生内存溢出之前,会对其及逆行回收;
  • 弱引用:每次GC发生时都会进行回收;
  • 虚引用:无法使用,只是在对象被回收时发起一个系统通知。

2、垃圾回收算法

(1)标记清除算法(老年代回收算法)

算法分为两个阶段:

  • 标记:标记出所有需要回收的对象;
  • 清除:标记完成后统一回收所有被标记的对象。

缺陷:

  • 效率低:标记和清除过程效率都不高;
  • 清除后产生大量不连续的内存碎片,导致在之后的运行中需要分配较大对象时,无法找到足够的连续内存不得不提前进行下一次垃圾回收。
(2)复制算法(新生代算法)

复制算法解决了”标记-清理“的效率问题。将可用的内存按容量分为大小相等的两块,每次只使用一块。当内存需要进行垃圾回收时,会将该区域存活的对象复制到另一块上面,然后将已经使用过的内存区域清理掉。

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

5c96d4d7e419e805d14d06f4e2bb7.png)

(2)复制算法(新生代算法)

复制算法解决了”标记-清理“的效率问题。将可用的内存按容量分为大小相等的两块,每次只使用一块。当内存需要进行垃圾回收时,会将该区域存活的对象复制到另一块上面,然后将已经使用过的内存区域清理掉。

[外链图片转存中…(img-EzavD0pn-1714413429382)]
[外链图片转存中…(img-4EaXRBQm-1714413429383)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值