是什么?
Java Virtual Machine Java虚拟机。
内存模型
基于线程安全提出的。
Java Memory Model,JMM。屏蔽掉各种硬件和操作系统的内存访问差异。
Java内存模型规定了所有的变量都存储在主内存中,每条线程还要自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝。线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主存来完成。
内存结构?
程序计数器:存放当前线程字节码指令地址,当线程切换后可以回到正确的位置。
虚拟机栈:需要的数据,指令,要返回的地址,可以类比一个方法,需要的数据就是行参,指令就会逻辑代码,返回地址就是返回值。
本地方法栈:为执行本地方法服务的。
方法区:常量 静态变量 类信息
堆:对象
metaspace就是java8中方法区(永久代)的实现
什么时候回收?
1。执行system.gc()手动调用gc方法的时候
2。堆区空间不足的时候,分为新生代空间不足触发minor gc,老年代空间不足触发full gc
哪些内存需要回收?
gc回收的是方法区和堆区。线程公有,其他三个都是线程私有,随线程终止而消失。
当一个对象通过引用计数法计数器为0或者可达性分析不可达的时候就需要进行回收。
引用计数法:
给一个对象添加一个引用计数器。每次有一个地方引用时,计数器加1,当失去引用时计数器减1。当计数器为0时说明对象不再使用。
此时A->B B->A,A和B互相引用计数器都为1,都不能被回收。
public class Test{
Object object1 = new Object(); //计数为1
Object object2 = new Object(); //计数为1
object1.ref = object2; //计数为2
object2.ref = object1; //计数为2
object1 = null; //计数为1
object2 = null; //计数为2
}
可达性分析法:
通过一系列的根节点向下搜索,走过的路径被称为引用链,当一个对象到根节点没有任何一个引用链时,对象不可用。
解决了引用计数法的问题,但是不可达不一定会立刻回收,finalize方法会返回一次,重新建立引用连接。上图ABC都会回收。
什么样的对象会成为根节点呢?
类加载器 常量 static成员变量
怎么回收?
垃圾回收算法
理论
标记清除
先标记可回收的对象,然后进行回收,产生碎片。
复制
先把内存分成大小相同的两块,每次只使用其中的一块,当这一块内存用完了,就将还存活的对象复制到另一块上面,然后把已使用过的内存空间一次清理掉,效率高,空间利用率不高,因为每次都只使用其中的一块内存。
标记整理
将所有存活的对象都向一端移动。没有内存碎片,时间长。
分代回收
yong区采用复制算法
old区采用标记清除或者标记整理算法
分区回收
把内存分成等份的区域,每个小空间可以单独使用,细粒度划分可以单独回收,减少了FullGC发生的频率。
垃圾收集器
进行垃圾回收。
Parallel Collector 并行收集器
不能一边进行垃圾回收一边工作,关注吞吐量
并行说的是可以有多个线程同时执行垃圾回收,此时用户线程等待。吞吐量高(用户线程时间/用户线程时间+垃圾回收时间),用户线程时间执行的时间长。
CMS Collector 并发收集器
关注响应时间,并发。
垃圾回收线程和用户工作线程可以同时执行,用户工作线程的时间短,响应时间短。
G1收集器
分区算法
垃圾区搭配使用
JVM运行流程
java里面最小的单元是线程。
一个类要运行的时候首先经过class编译成字节码文件,类加载,连接,扔到JVM(运行时数据区)进行初始化,使用,卸载。
JVM基本结构
类加载器, 执行引擎, 运行时数据区,本地接口 ,本地方法库
类加载过程
jvm把class文件加载到内存,并对数据进行校验,解析和初始化,最终形成jvm可以直接使用的java类型。
加载:通过ClassLoader加载class文件字节码,生成Class对象
链接:分为校验,转备和解析(不是必须的)。
验证:检查加载的class的正确性和安全性
准备:为类变量分配存储空间并设置类变量初始值
解析:JVM将常量池中的符号引用转换为直接引用
初始化:执行类变量赋值(用static修饰的变量)和静态代码块(static方法)
类加载器
在类加载成class对象的时候起作用。
类名.class.classloader打印当前的加载器
启动加载器
BootStrap Classloader 主要加载 rt.jar
扩展类加载器
Extension Classloader extends classloader 加载 java/home/lib/ext*.jar
应用类加载器
App Classloader extends Classloader 加载 classpath中的类库
自定义类加载器
extends classloader 完全自定义加载路径
这四种类加载器从上到下是父子关系,但是不是继承关系,是组合关系,就是成员变量。在自类加载器里有父类的变量就是组合关系。
双亲委派模型
loadclass (从classloader中查看源码)
parent是类变量,这里体现的不是继承关系。
类加载之前先查询是否被加载过,如果有则返回,否则为null,往下执行。当parent!=null 的时候调用父类的loadclass()方法查询是否被加载过一直反复执行这个方法,当时启动类加载器BootStrap Classloader的时候parent= null,查询启动类加载器是否加载过这个类,如果没有在启动类加载器里寻找是否有这个类文件如果还是没有,到下面的if(c==null)在扩展,应用类加载器里查找是否有这个类文件,此时还没有就调用子类自己写的findclass方法,表面是findclass(),实际上真正加载的是defineclass()这个方法。
JVM锁分类
偏向锁
轻量级锁
重量级锁
自旋锁