JVM概述
Java虚拟机
类加载机制
对象实例化的过程
对象引用是存放在站里面的,正真的值是存放在堆里面的。
类加载器
- 虚拟机自带的加载器
- 启动类(根)加载器
c++
编写,加载java
核心库 java.*
,构造ExtClassLoader
和AppClassLoader
。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作
- 扩展类加载器
java
编写,加载扩展库,如classpath
中的jre
,javax.*
或者
java.ext.dir
指定位置中的类,开发者可以直接使用标准扩展类加载器。
- 应用程序加载器
``java编写,加载程序所在的目录,如
user.dir所在的位置的
class`
- CustomClassLoader(用户自定义类加载器)
java
编写,用户自定义的类加载器,可加载指定路径的class
文件
双亲委派机制
作用:
- 防止重复加载同一个
.class
。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。 - 保证核心
.class
不能被篡改。通过委托方式,不会去篡改核心.clas
,即使篡改也不会去加载,即使加载也不会是同一个.class
对象了。不同的加载器加载同一个.class
也不是同一个Class
对象。这样保证了Class
执行安全。
向上委派,向下加载
Native关键字
- 凡是带了native关键字的,说明java的作用范围达不到了,回去调用底层C语言的库!
- 会进入本地方法栈
- 作用是扩展java的使用
PC寄存器
程序计数器: Program Counter Register
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向像一条指令的地址,也即将要执行的指令代码),在执行弓|擎读取下一条指令,是一个非常小的内存空间,几乎可以
忽略不计。
方法区
方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,
简单说,**所有定义方法的信息都保存在该区域,此区域属于共享区间; **
静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存
中,和方法区无关
存放 static final Class模板 常量池~
栈
- 占内存主管程序的运行,生命周期和线程同步,线程结束,栈内存也就随之释放,不存在垃圾回收。
- 栈里面存储的东西是: 八大基本数据类型+对象引用+实例方法
栈+堆+方法区的交互:
对象实例化的过程
https://mp.weixin.qq.com/s/JD298UZ-1q8YuV5ft3RDWA
- 类的加载初始化
- 对象的初始化
堆
-
GC垃圾回收主要发生在伊甸园区和养老区
-
内存满了,堆内存不够,有OOM错误
永久区
这个区域用来常驻内存,存储JDK自带的class对象,接口元数据,类信息~,这个区域不存在垃圾回收!关闭JVM虚拟就会释放这个区域。
GC垃圾回收机制
作用区域: 堆+方法区(逻辑上属于堆)
JVM在进行GC时,并不是对这三个区域统- -回收。大部分时候,回收都是新生代~
-
伊甸园区
-
幸存区(form, to)
-
老年区
GC两种类:轻GC (普通的GC), 重GC (全局GC)
怎么判断对象是否死亡
可达性分析算法
此算法的核心思想:通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为“引用链”,当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用。
在Java语言中,可作为GC Roots的对象包含以下几种:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象。
- 方法区中静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中(Native方法)引用的对象
GC的算法有哪些?
标记清除法,标记压缩,复制算法,引用计数器,怎么用的?
轻GC和重GC分别在什么时候发生?
复制算法
动态理解:
优点:没有内存碎片
缺点:浪费了内存空间~ 因为有一半幸存区永远是空的。
标记清除法
- 对一些有用的对象进行扫描标记
- 清除没有标记的对象。
总结
- 内存效率:复制算法>标记清除算法>标记压缩算法(时间复 杂度)
- 内存整齐度:复制算法=标记压缩算法>标记清除算法
- 内存利用率:标记压缩算法=标记清除算法>复制算法
- 新生代(存活率低):复制算法 养老区:标记清除