JVM原理 ,GC工作机制详解( Java Virtual Machine )

一、JVM结构
1.GC是负责回收所有无任何引用对象的内存空间。注意:垃圾回收回收的是无任何引用的对象占用的内存空间而不是对象本身
2.GC回收机制的两种算法,a.引用技术法,b.可达性分析算法
(1)类加载器(classloader):在JVM启动时或者在类运行时将需要的class加载到JVM中。
为什么要知道类加载机制
按需加载:JVM启动时不能确定我们需要加载哪些东西,或者有些类非常大,我只希望用到它的时候加载,并非一次性加载所有的class,所以这个时候要了解加载机制就可以按需加载了
类隔离:在部署多个应用,应用之间互相可能会有冲突,希望尽量隔离,这里可能就要分析应用加载的资源和加载顺序之间的冲突,针对这些冲突自己定义规则
资源回收:如果你不了解java如何加载资源的,需要理解Java的加载机制
一般说到java的类加载机制都要提到"双亲委派模型",这种机制,可以避免重复加载,当父类已经加载了该类的时候,就没有比较子classloader再加载一次,JVM会根据类名+包名+classloader实例ID来判断两个类是否相同,是否加载过。
类加载顺序
bootsrapclassloader ----->extensionclassloader---->appclassloader---->customclassloader
检查类是否已经加载方向和类加载顺序相反
bootstrapclassloader:他时最顶级的类加载器,是由C++编写而成,已经内嵌到JVM中了,在JVM启动的时候会初始化该classloader,它主要作用时来读取java的核心类库JRE/lib/rt.jar中的所有class文件,这个jar中包含了java规范定义的所有接口和实现。
extensionclassloader:他时用来读取java的一些扩展类库,如读取JRE/lib/ext/*.jar
appclassloader:他是用来读取classpath下指定的所有jar包或目录的类文件,一般情况下这就是程序默认的类加载器
customclassloder:他是用户自定义编写的,它用来读取指定类文件。基于自定义的classloader用户加载非classpath中的jar和目录(如网络下载下载的jar或则二进制文件),还可以加载之前class文件优化一些动作,如解密,编码等
(2)执行引擎:负责执行class文件中包含的字节码指令
(3)内存区(运行时数据区):在JVM运行时候操作所分配的内存。运行时内存主要可以划分5个区域
方法区:用于存储类结构信息的地方,包括常量池,静态变量,构造函数等,运行时常量池
java堆(heap):存储java实例或者对象的地方,这一块是GC的主要区域,这个堆是所有java线程共享的
java栈(stack):栈总是和线程关联在一起,每当创建一个线程时,JVM就会为这个线程创建一个对应的java栈,在这个java栈中又会包含多个栈帧,每运行一个方法就 创建一个栈帧,用户存储局部变量,操作栈,方法返回值,每个方法从调用直至完成的过程,就对应着一个栈帧在java的入栈到出栈的过程,栈线程私有的。
程序计数器(PC register):用于保存当前线程执行的内存地址,由于JVM程序时多线程执行的(线程轮流切换),所以为了保证线程切换回来后,还能恢复到原先状 态,就需要一个独立的计数器,记录之前中断的地方,可见程序计数器也是线程私有的。
本地方法栈:和java栈的作用差不多,不过时为了JVM使用到的native方法服务的。
(4)本地方法接口:主要时调用C或C++实现的本地方法以及返回结果。
二、内存分配
java内存申请:静态内存和动态内存
java栈、程序计数器、本地方法栈都是线程私有的线程在就在,销毁就消失。内存也跟着回收这个几个区域内存分配和回收时确定的,但是java堆和方法区不一样,我们只能在程序运行期间才知道会创建哪些对象,所以这部分内存分配和回收时动态的。一般来说垃圾回收时针对的这一部分。
三、垃圾检测、回收算法
垃圾收集器:检测垃圾,回收垃圾
检测垃圾:
引用技术法:给一个对象添加引用计数器,每当有个地方引用它,计数器就加一;引用失效计数器就 减一。A对象引用B ,B对象引用A 会有问题
可达性分析法:解决上面相互引用的问题 GC Roots 扫描
垃圾回收算法:
标记-清除法
复制
标记-整理(标记-清除和复制算法优点结合)
分代收集算法
类的生命周期:
加载 连接 初始化 使用 卸载
四、Java中堆和栈的区别?
栈:(1)线程私有的内存区域。
(2)每个线程在创建的时候都会分配一个独立的栈
(3)主要用于存储方法执行时候的栈帧(帧弹出销毁,不涉及垃圾回收,栈自己管理)
(4)天然线程安全(私有)
(5)无碎片化的内存问题
(6)后进先出
堆:(1)线程共享的内存区域.
(2)JVM启动时创建,整个JVM只有一个堆。
(3)主要用于存储对象实例和数组(new 创建的对象)
(4)垃圾回收的主要区域
五、JVM为什么使用元空间替换永久代?
|---------|------------------------|--------------------|
| 对比维度 | 永久代 | 元空间 |
| 内存区域 | JVM堆内存的一部分 | 本地内存 |
| 大小限制 | 固定范围大小(64M-1GB),需要手动配置 | 动态扩展,默认无上限(物理内存限制) |
| 内存溢出风险 | 高(容易因为类多触发OOM) | 低 |
| 垃圾回收 | 与老年代绑定,回收效率低 | 独立回收,针对无用的类 |
| 跨虚拟机兼容性 | 仅支持HotSpot支持 | 所有JVM实现统一支持 |