0
点赞
收藏
分享

微信扫一扫

JVM知识-对象产生过程-垃圾收集器

你的益达233 2022-04-21 阅读 99
后端java

运行时数据区域

线程私有的:

**程序计数器:**字节码解释器依次读取指令;恢复线程切换的位置。唯一不会出现 OutOfMemoryError
虚拟机栈:(StackOverFlowError,OutOfMemoryError)方法压栈弹栈,栈由一个个栈帧组成,而每个栈帧中都拥有:
**局部变量表:**编译期可知的各种数据类型;对象引用操作数栈:存放方法执行过程中产生的中间计算结果
动态链接:当一个方法要调用其他方法,需要将常量池中指向方法的符号引用转化为其在内存地址中的直接引用。动态链接的作用就是为了将符号引用转换为调用方法的直接引用。
**方法返回地址:**执行完方法后返回上一次的地址
**本地方法栈:**虚拟机使用到的 Native 方法服务

线程共享的:

**堆:**对象实例,字符串常量池,几乎所有的对象实例以及数组都在这里分配内存。垃圾收集器管理(将堆分为Eden、Survivor、Old)
Eden:对象产生(小部分的大对象直接进入老年代)。(不足空间进行MinorGC,若无法进入FROM区,则使用分配担保机制把新生代的对象提前转移到老年代中去,老年代上的空间足够存放)
From:年纪加1
To:GC对换from
Old:15老龄
**方法区(元空间/永久代):**读取并解析 Class 文件。类信息、字段信息、方法信息、常量、静态变量、即时编译器编译后的代码缓存等数据。常量池表会在类加载后存放到方法区的运行时常量池中。
直接内存: NIO(New Input/Output) 类直接使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆之间来回复制数据。

类文件结构

**魔数(magic):**确定这个文件是否为一个能被虚拟机接收的 Class 文件。
**Class文件版本号:**低版本编译器无法编译高版本编译器
常量池(Constant Pool):
1.字面量:文本字符串、声明为 final 的常量值
2.符号引用:类和接口的全限定名;字段的名称和描述符;方法的名称和描述符。
3.访问标志(Access Flags):识别一些类或者接口层次的访问信息
4.当前类(This Class)、父类(Super Class)、接口(Interfaces)索引集合
5.字段表集合(Fields):字段的作用域;名称;描述符;内容
6.方法表集合(Methods):访问标志、名称索引、描述符索引、属性表集合

类加载过程

加载->连接(验证->准备->解析)->初始化
加载:
1.通过全类名获取定义此类的二进制字节流
2.将字节流所代表的静态存储结构转换为方法区的运行时数据结构
3.在内存中生成一个代表该类的 Class 对象,作为方法区这些数据的访问入口
验证:
文件格式验证
元数据验证:是否有父类
字节码验证
准备:正式为类变量分配内存并设置类变量初始值的阶段
解析:将常量池内的符号引用替换为直接引用的过程
初始化:初始化阶段是执行初始化方法 ()方法的过程,是类加载的最后一步

类加载器

BootstrapClassLoader(启动类加载器):最顶层的加载类,由 C++实现,负责加载 %JAVA_HOME%/lib目录下的jar 包和类或者被 -Xbootclasspath参数指定的路径中的所有类。
ExtensionClassLoader(扩展类加载器) :主要负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类,或被 java.ext.dirs 系统变量所指定的路径下的 jar 包。
AppClassLoader(应用程序类加载器):责加载当前应用 classpath 下的所有 jar 包和类。

双亲委派机制:啃老族
类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。加载的时候,首先会把该请求委派给父类加载器的 loadClass() 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader 中。当父类加载器无法处理时,才由自己来处理。

双亲委派模型的好处:
避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类)

创建对象的过程

类加载检查:检查常量池的符号引用,是否已被加载过
分配内存:新生对象分配内存。分配方式有 “指针碰撞” 和 “空闲列表” 。

  1. 指针碰撞:适用场合 :堆内存规整(即没有内存碎片)的情况下。 原理 :有用的内存全部整合到一边,没有用过的内存放在另一边,中间有一个分界指针,只需要向着没用过的内存方向将该指针移动对象内存大小位置即可。使用该分配方式的
    GC 收集器:Serial, ParNew

  2. 空闲列表:适用场合 : 堆内存不规整的情况下。 原理 :虚拟机会维护一个列表,该列表中会记录哪些内存块是可用的,在分配的时候,找一块儿足够大的内存块儿来划分给对象实例,最后更新列表记录。使用该分配方式的
    GC 收集器:CMS

  3. 内存分配并发问题:虚拟机采用两种方式来保证线程安全TLAB:为每一个线程预先在 Eden 区分配一块儿内存,JVM 在给线程中的对象分配内存时,首先在 TLAB 分配,当对象大于 TLAB 中的剩余内存或 TLAB 的内存已用尽时,再采用上述的 CAS
    进行内存分配CAS+失败重试:乐观锁机制

初始化零值:分配到的内存空间都初始化为零值
设置对象头:标记字段,类型指针,补充位
执行 init 方法

对象的访问定位

通过栈上的 reference 数据来操作堆上的具体对象。对象的访问方式由虚拟机实现而定,目前主流的访问方式有:使用句柄、直接指针。

  1. 句柄:Java 堆中将会划分出一块内存来作为句柄池,本地方法栈的reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息,然后到堆寻找对象实例,到方法区寻找对象类型数据。
  2. 直接指针:java堆中,直接将对象实例和到对象类型数据的指针封装在一起,reference中存储的直接就是对象的地址,然后直接寻找堆中的对象实例,再找到对象类型数据

对象的消亡

  1. 引用计数法:给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减1;任何时候计数器为 0的对象就是不可能再被使用的。(相互循环引用问题)
  2. 可达性分析算法:GCRoots对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的,需要被回收。 GC Roots:栈中引用的对象;方法区中引用的对象;同步锁持有的对象

引用

强引用:new出来的对象
软引用:引用队列(ReferenceQueue)
弱引用:引用队列(ReferenceQueue)
虚引用:引用队列(ReferenceQueue)

垃圾回收

部分收集:
新生代收集(Minor GC):
老年代收集(Major GC):
混合收集(Mixed GC):
整堆收集 (Full GC):

垃圾收集算法:

标记-清除算法:标记清除后会产生大量不连续的碎片
标记-复制算法:对半内存数据
标记-整理算法:移动清除

垃圾收集器:

结合场景选择适合的垃圾收集器

  1. Serial 收集器:单线程,暂停工作线程。新生代采用标记-复制算法,老年代采用标记-整理算法。
  2. ParNew收集器:多线程,暂停工作线程。新生代采用标记-复制算法,老年代采用标记-整理算法。
  3. Parallel Scavenge收集器:多线程,用户线程的停顿时间(提高吞吐量)。新生代采用标记-复制算法,老年代采用标记-整理算法。
  4. Serial Old 收集器:单线程,老年代。 Parallel Old 收集器:多线程,老年代。
  5. CMS收集器:以获取最短回收停顿时间为目标的收集器。垃圾收集线程与用户线程(基本上)同时工作。基于标记-清除算法。
    整个过程分为四个步骤:
    初始标记:暂停所有的其他线程,并记录下直接与 root 相连的对象 并发标记:同时开启 GC 和用户线程,记录可达对象
    重新标记:为了修正并发标记期间改变的标记记录 并发清除:开启用户线程,同时 GC 线程开始对未标记的区域做清扫。
  6. G1收集器:面向服务器的,使用多个 CPU。基于标记-整理算法。
    初始标记
    并发标记
    最终标记
    筛选回收

JVM 参数总结

堆内存:

–Xms
-Xmx
-XX:NewSize /-Xmn
-XX:MaxNewSize
-XX:NewRatio 新生代和老年代的比例 NewRatio 默认为 2
-XX:MetaspaceSize设置 Metaspace 的初始
-XX:MaxMetaspaceSize设置 Metaspace 的最大大小

垃圾收集相关:

-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+UseParNewGC
-XX:+UseG1GC

JDK 监控:

jps:用于查看所有 Java 进程的启动类、传入参数和 Java 虚拟机参数等信息
jmap:生成堆转储快照;
jhat:用于分析 heapdump 文件
jstack:生成虚拟机当前时刻的线程快照
JDK 可视化分析工具:
JConsole: JDK 目录下的 bin 目录

举报

相关推荐

0 条评论