JVM相关

JVM的主要职责管理内存

JVM基础

JVM的内部结构

JVM内部结构.jpg
  • JAVA 堆(heap):是java 虚拟机所管理的内存中最大的一块,存放对象实例,即new的对象和数组(可以被所有的线程共享,不会存放别的对象引用)
  • 方法区:用于存储已经被虚拟机加载的类、常量和静态变量 (可以被所有的线程共享,包含了所有的class和static变量)
  • 程序计数器:是一块较小的内存空间,作用是当前线程所执行的字节码行号指示器
  • JVM栈:是虚拟机描述的JAVA 方法执行的内存模型,每个方法被执行的时候都会创建一个栈帧,用于存放局部变量表、操作栈、动态链接、方法出口等信息(存放基本变量类型(含具体数值),引用对象的变量(存放引用在堆里的具体地址))
  • 本地方法栈:与JVM栈作用类似,区别是本地方法栈是为Native方法服务的,JVM栈是为java方法服务

JVM中那些是共享区,那些可以作为GcRoot

  • 堆和方法区是所有线程共享的,栈、本地方法栈、程序计数器是每个线程独有的
  • 栈中的本地变量,本地方法栈中的变量、方法区的静态变量、正在运行的线程可以作为GcRoot

内存回收机制

内存回收的几种算法

  • 标记清除算法 :标记清除算法主要分为有两个阶段,首先标记出需要回收的对象,然后咋标记完成后统一回收所有标记的对象; 缺点:
    效率问题:标记和清除两个过程效率都不高。
    空间问题:标记清除之后会导致很多不连续的内存碎片,会导致需要分配大对象时无法找到足够的连续空间而
    不得不触发GC的问题。

  • 复制算法 :将可用内存按空间分为大小相同的两小块,每次只使用其中的一块,等这块内存使用完了将还存活的对象复制到另一块内存上,然后将这块内存区域对象整体清除掉。每次对整个半区进行内存回收,不会导致碎片问题,实现简单且效率高效。 缺点: 需要将内存缩小为原来的一半,空间代价太高。

  • 标记整理算法:标记整理算法标记过程和标记清除算法一样,但清除过程并不是对可回收对象直接清理,而是将所有存活对象像一端移动,然后集中清理到端边界以外的内存。

  • 分代回收算法 :当代虚拟机垃圾回收算法都采用分代收集算法来收集,根据对象存活周期不同将内存划分为新生代和老年代(新生代经过多次垃圾回收机制后都没有被回收就会被放入老年代),再根据每个年代的特点采用最合适的回收算法。

    新生代存活对象较少,每次垃圾回收都有大量对象死去,一般采用复制算法,只需要付出复制少量存活对象的
    成本就可以实现垃圾回收;
    老年代存活对象较多,没有额外空间进行分配担保,就必须采用标记清除算法和标记整理算法进行回收;

  • 效率对比
    效率: 复制算法 > 整理算法 > 清除算法
    内存整齐度:复制算法 = 整理算法 > 清除算法
    内存使用率:整理算法 = 清除算法 > 复制算法

分代机制

  • 年轻代:用来存放新建的对象,死亡快存在朝生夕死的情况(使用复制算法)
  • 老年代:老年代中存放的对象是存活了很久的,如年轻代经历多次垃圾回收仍存活就会被放入老年代(清除和整理算法)

GC如何判断一个对象可以被回收

  • 引用计数法:每个对象都有一个引用技术属性,新增一个引用计数加一,引用释放的时候计数减一,计数为零的时候表示可以回收
  • 可达性分析法:从GcRoots 开始向下搜索,搜索所有走过的路劲称之为引用链,当一个对象到GcRoots没有任何引用链时,则证明引用对象是不可用的,那么虚拟机就判断是可回收对象
  • 引用计数法可能会出现A引用了B,B又引用了A,这个时候就会出现他们都不再使用了,但因为计数器为1永远无法被回收
  • 可达性算法中不可达对象并不是立即死亡的,对象被宣告死亡至少要经历两次标记过程,第一次是可达性分析算法发现没有引用链,第二次是由虚拟机建立的finalizer队列中判断是否需要执行finalizer()方法。如果对象在进行可达性分析后发现没有与任何的 “GC Roots” 引用链相连接,则会被第一次标记,随后会进行一次筛选过程,筛选的条件是 “该对象是否有必要执行 finalize() 方法”。只有在该对象没有覆盖 finalize() 方法,或者 finalize() 方法已经被虚拟机调用过 时,才认为是 “没有必要执行”。

GcRoot 的对象有哪些

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(即一般说的Native方法)中引用的对象
  • JVM的内部引用(Class 对象、异常对象NullPointException 。。。。、系统类加载器)
  • 所有被同步锁(Synchronized关键字)持有的对象
  • JVM内部的JMXBean 、JVMTI中注册的回调,本地缓存等
  • JVM实现中的临时性对象,跨代引用的对象(在分代回收只回收部分代时)
  • 正在运行的变量在当前时刻都可以称之为GcRoot,存在虚拟机栈中

native 层也是用户空间,用户空间和内核空间唯一的通讯方式就是系统调用

GC的几种引用方式

  • 强引用:默认的引用方式
  • 软引用:内存不足时回收
  • 弱引用: GC 到来时回收 (除了强引用用的最多的引用)
  • 虚引用:GC回收后可以得到一个通知

垃圾回收器

  • CMS:核心思想就是将STW打散,让一部分GC线程与用户线程并发执行(concurrent mark sweep)
    初始标记→并发标记 → 重新标记 → 并发清除
    ①、STW只标记出根对象直接引用的对象
    ②、继续标记其他对象与应用程序并发执行
    ③、STW对并发执行阶段的对象重新标记
    ④、并行将产生的垃圾清除,清除过程中优惠产生付浮动垃圾下次清除
  • G1垃圾优先:他的内存模型中对于堆内存不再分代,而是分成一个个Region的小块,每个Region可以隶属不同的年代(实际不分代,逻辑分代)
    初始标记→ 标记Region → 并发标记 → 重新标记 → 回收
    ①、标记出GCRoot 直接引用的对象 STW
    ②、通过rest 标记出上个阶段标记的Region引用到的old区Region
    ③、跟CMS差不多,但是遍历范围不在是整个old区,而只需要遍历第二步标记出来的Region
    ④、和CMS差不多
    ⑤、和CMS不一样,G1采用拷贝算法,G1只选择垃圾多的清理
  • CMS 核心算法:三色标记:是一种逻辑上的抽象,将每个内存对象分成三种颜色
    黑色:自己和成员变量都标记完
    灰色:自己标记完了
    白色:自己未标记
    通过增量标记解决漏标问题

类加载

类的生命周期

类的生命周期
  • 加载:查找并加载类的class 文件,将class文件字节码内容加载到内存中,并将这些数据转换成方法区的运行时数据结构,然后生成代表这个类的java.lang.class 对象
  • 链接:包括验证、准备、和解析三个阶段,将java类的二进制代码合并到JVM的运行状态之中的过程
  • 验证:确保被导入的类型的正确性
  • 准备:为类的静态字段分配字段并默认初始化这些字段
  • 解析:虚拟机常量池内的符号引用替换成直接引用
  • 初始化:将类变量初始化为正确的初始值

类加载器

  • 根加载器 :用来加载核心库,JVM自带的类加载器
  • 扩展类加载器:负责jre/lib/ext目录下的jar包或者java.ext.dirs指定目录下的jar包装入工作库
  • 系统类加载器:咱自己的类加载器
    根加载器和扩展类加载器 负责加载javaHome 下的所有jar包和class文件

双亲委托机制

  • 向上委派:实际上就是查找缓存,是否加载了该类,有则返回,没有则继续向上委派到顶层后缓存中还是没有,则到加载路径中查找,有则返回,没有则向下查找
  • 向下查找:查找加载路径,有则返回没有则向下查找
    向上委派到类加载器为止,向下查找到发起类加载的加载器为止
    双亲委托机制的意义:
    安全性:避免用户些的类替换了java 核心类
    同时也避免了类的重复加载,因为jvm中区分类的不同,不仅仅是根据类名,相同class文件被不同加载器加载也会是两个不同类

类加载器的作用

将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区运行时数据结构,然后再堆中生成一个代表这个类的class对象,作为方法区中类数据的访问入口

类缓存

标准的JavaSE 类加载器可以按照要求查找类,但一旦某个类被加载到类加载中,他将维持加载一段时间,不过JVM垃圾回收机制可以回收这些class对象

对象的创建

  • 判断对象对应的类是否创建
  • 为对象分配内存空间,两种方式
    a、指针碰撞:找到空闲指针,然后从开始位置往后移n个指针(内存空间规整)
    b、空闲列表:从空闲列表中找到满足条件的内存空间
  • 处理并发安全问题
    a、 CAS算法配上失败重试机制
    b、本地线程分配缓冲区
  • 初始化分配到的内存空间
    将分配到的内存空间出对象头之外都初始化为零
  • 设置对象的对象头
    将对象的所属类,对象的HashCode 和对象的GC分代数据存储在对象头中
  • 执行init 方法进行初始化
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1、JVM内存模型 JVM内存模型主要有五个部分组成:程序计数器、虚拟机栈、本地方法栈、方法区、堆 程序计数器 程...
    小胖六阅读 537评论 1 0
  • 3、垃圾回收 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 ...
    脆皮鸡大虾阅读 312评论 0 0
  • 一、JVM = 类加载器(classloader) + 执行引擎(execution engine) + 运行时数...
    大树8026阅读 364评论 0 3
  • 1. 如何判断对象可以回收? 1.1 引用计数法 算法:在对象中添加一个引用计数器,每当有一个地方引用它时,计数器...
    lilykeke阅读 251评论 0 0
  • JVM内存模型 JVM主要由堆内存,方法区,程序计数器,虚拟机栈,本地方法栈组成,其中对堆内存和方法区是线程共有的...
    Rain_z阅读 313评论 0 0

友情链接更多精彩内容