JVM_概念_回收算法_JVM学习笔记(一)

一、运行时数据区域

在这里插入图片描述

  1. 程序计数器
    记录当前线程执行到字节码的行号,各个线程之间相互独立,程序的分支、循环、跳转、异常处理、线程恢复(中断后唤醒)等基础功能都依赖于程序计数器完成。

  2. Java 虚拟机栈
    线程私有,每个方法被执行的时候,都会创建一个栈帧(局部变量表、操作数栈、动态连接、方法出口)
    在这里插入图片描述

  3. 本地方法栈
    为虚拟机使用到的本地方法服务

  4. JAVA堆
    JAVA堆是所有线程共享的内存区域,除了栈上分配是在栈上分配空间,几乎所有对象的实例都存放在堆中。
    堆内存分配常用的命令:

    -Xms:堆的最小值;
    -Xmx:堆的最大值;
    -Xmn:新生代的大小;
    -XX:NewSize;新生代最小值;
    -XX:MaxNewSize:新生代最大值;
    :- Xmx500m
    

    栈上分配:如果这个类经过逃逸分析逃不出方法体,则这个对象的实例就是栈上分配,随着方法的执行完成而结束(只有JVM运行模式是server模式才能进行逃逸分析)。

    逃逸分析:其实就是分析当前对象的实例会不会成为方法的返回值返回到上一个方法中。

    -server(JVM运行模式)
    -XX:+DoEscapeAnalysis:启用逃逸分析(默认打开)
    -XX:+EliminateAllocations:标量替换(默认打开)
    这三个都必须打开才能使用逃逸分析
    
  5. 方法区(元空间)
    用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
    JDK1.8之后方法区变成了元空间,并且改为采用本地内存中实现。
    配置参数如下:

    jdk1.8 之前 
    	非堆区初始内存分配大小:-XX:PermSize;
    	非堆区分配的内存的最大上限 :-XX:MaxPermSize
    jdk1.8
    	非堆区初始内存分配大小:-XX:MetaspaceSize; 
    	非堆区分配的内存的最大上限 :-XX:MaxMetaspaceSize
    
  6. 直接内存
    用于NIO,避免在JAVA堆和Native堆中来回复制数据,使用Native函数库直接分配堆外内存,可以显著提高数据或文件传输的性能。
    直接内存受本机总内存的限制(默认与堆内存最大值一样),内存不足时抛出OutOf-MemoryError或
    者OutOfMemoryError: Direct buffer memory。

    设置直接内存的大小
    -XX:MaxDirectMemorySize
    

二、JVM 垃圾收集算法

  1. 判断对象是否可被回收算法
    a. 引用计数法:当有一个引用该对象计算器就加一,引用失效时就减一,如果计算器为零则表示没 有被使用, 可被回收。

    b.可达性分析算法:通过根对象(GC Roots)作为起始节点,根据引用关系向下搜索,搜索过程走过的路径称为"引用链",如果某个对象到GC ROOT间没有任何引用链相连,即这个对象不可达,不可达的对象可被回收。
    在这里插入图片描述

  2. 垃圾收集算法
    通过分代收集理论,收集器将Java堆划分出不用的区域。
    在这里插入图片描述
    a、标记-清除算法
    算法分为标记和清除两个阶段,首先标记出所有需要回收的对象,标记完成后,统一回收掉所有被标记的对象。
    缺点: 内存空间碎片化。
    在这里插入图片描述
    b、标记-复制算法*
    标记-清除的改进版,将可用内存按照容量划分为大小相等的两块,每次将存活着的对象复制到另外一块区域上,在把使用过的内存空间一次性清理掉,不存在空间碎片化问题。
    缺点:浪费空间,如果对象存活率较高,会进行较多次的复制操作,效率降低。
    在这里插入图片描述
    c、标记-整理算法*
    对可回收的对象进行标记之后,将存活的对象向内存空间一端移动,然后直接清理掉边界以外的内存。
    在这里插入图片描述

     年轻代:使用标记-复制算法
     老年代:使用标记-整理算法,因为老年代每次回收都有大量对象存活区域,不适合使用标记复制。
    

三、JVM 常见垃圾收集器

各个收集器连线表示可搭配使用
在这里插入图片描述
a. 吞吐量优先组合:Parallel Scavenge + Parallel Old
吞吐量 = 运行用户代码时间/(运行用户代码时间+运行垃圾收集时间)
例: 运行用户代码时间(99分钟)/运行用户代码时间(99分钟)+运行垃圾收集时间(1分钟) =99%

b.最短回收停顿时间组合:CMS(标记-清除算法) + ParNew

c. G1收集器: 面向服务端应用的垃圾收集器,JDK9 取代 Parallel Scavenge + Parallel Old组合,CMS收集器也随之废弃,G1分区大小不再固定大小以及固定数量,G1收集器衡量标准不再是属于哪个分代,而是那块内存中存放的垃圾数量最多,回收收益最大

使用G1收集器
-XX:+UseG1GC
查看当前使用的垃圾收集器命令,在linux操作系统或者在windows cmd命令中执行如下命令:
java -XX:+PrintCommandLineFlags -version

在这里插入图片描述

小结:JVM在进行垃圾回收的时候,会暂停用户应用程序,这种停顿被称为"Stop The World",调优本质上调的就是尽量减少Full GC ( Minor GC 、Major GC次数)。

JVM问题汇总
1.运行时数据区中包含哪些区域?哪些线程共享?哪些线程独享
共享:方法区(元数据)、堆
独享:程序计数器、虚拟机栈(局部变量表、操作数栈、动态连接、方法出口)、本地方法栈

  1. 说一下方法区和永久代的关系
    永久带是方法区的一种实现

  2. 讲一下 Java 创建一个对象的过程
    加载(二进制流、生成虚拟机的数据结构) -> 验证(是否代码符合规范) -> 准备(初始化数据) -> 解析(符号引用替换成直接引用) -> 初始化

  3. 对象的访问定位的两种方式
    句柄和直接指针两种方式

  4. 你了解分代理论吗?讲一下 Minor GC、还有 Full GC
    Minor GC(young gc):对象优先在Eden区分配,如果Eden区没有足够空间时,发生一次Minor GC,如果Eden区没有足够空间时,则分配到Survior区中,如果Survivor空间不足则分配到老年代中
    Full GC(Major GC): 在发生Minor GC之后,老年代空间不足则发生Full GC

    回收策略(内存分配策略):大对象直接进入老年代、长期存活的对象进入老年代(默认十五次)、动态对象年龄判定(如果Survivor相同年龄总和 > 1/2 Survivor )、空间分配担保

  5. Java 用什么方法确定哪些对象该被清理?讲一下可达性分析算法的流程
    引用计数、可达性分析(通过根对象GC Root作为起始点,根据引用关系向下搜索,搜索过程走过的路径成为引用链,如果某个对象到GCROOT没有任何引用链则被回收)

  6. JDK 中有几种引用类型?分别的特点是什么
    强引用 特点: 该对象不会被JVM回收,并且被引用对象可以直接访问目标对象,可能会导致内存泄漏(指不会被回收)
    软引用 特点: 使用 SoftReference类包装就是软引用,不会被JVM很快回收,JVM会根据当前堆的使用情况来判断何时回收
    弱引用 特点: 使用 WeakReference, 在系统GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收
    虚引用 特点: 使用 PhantomReference,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收

  7. 如何回收方法区?
    废弃的常量、不再使用的类型

  8. 标记清除、标记复制、标记整理分别是怎样清理垃圾的?各有什么优缺点?
    标记清除:标记出所有需要回收的对象,标记完成后,统一将该对象清除掉, 缺点:内存空间碎片化
    标记复制:将每次存活的对象复制到另一块区域,然后清除掉使用过的区域 缺点: 浪费空间,如果对象存活率高需要多次复制,效率低
    标记整理:对可回收的对象进行标记后,将存活的对象移动到空间的另一端,然后清空掉边界外以外的内存

10.JVM 中的安全点和安全区各代表什么?写屏障你了解吗?
安全点: 在特定的地方(方法调用、异常跳转、循环跳转)记录了Oopmap 数据结构,为了减少更新 OopMap 的开销。
安全区:代表在某段代码中,引用关系不会发生变化,线程执行到这个区域内是可以安全停下来进行GC的(处于Sleep 或者 Blocked 状态的线程无法跑到安全点)。
记忆集:是一种用于记录从非收集区域指向收集区域的指针集合的数据结构(为了解决对象跨代引用所带来的的问题)
卡表: 相当于记忆集数据结构的实现
写屏障:用于维护卡表 “引用类型字段赋值的状态

  1. 并发标记要解决什么问题?并发标记带来了什么问题?如何解决并发扫描时对象消失问题?。
    并发标记为了解决GC暂停用户线程,标记时间长的问题。
    带来的问题: 造成多标和漏标的问题
    解决方案: CMS是基于增量更新来做并发标记的(当一个白色对象被一个黑色对象引用,将黑色对象重新标记为灰色,让垃圾回收器重新扫描)
    G1则是用原始快照实现的(当原来成员变量的引用发生变化之前,记录下原来的引用对象,既原始快照,当B和C之间的引用马上被断掉时,将这个引用记录下来,使GC依旧能够访问到,那样白色就不会漏标)
    CMS、G1 垃圾收集器(三色标记算法、白色表示需要回收)
    白色:尚未被GC访问过的对象,如果全部标记已完成依旧为白色的,称为不可达对象,既垃圾对象。
    黑色:本对象已经被GC访问过,且本对象的子引用对象也已经被访问过了。
    灰色:本对象已访问过,但是本对象的子引用对象还没有被访问过,全部访问完会变成黑色,属于中间态。

  2. 新生代垃圾收集器有哪些?老年代垃圾收集器有哪些?哪些是单线程垃圾收集器,哪些是多线程垃圾收集器?各有什么特点?各基于哪一种垃圾收集算法?
    新生代(标记-复制): Serial 、 Parallel Scavenge、ParNew
    老年代(标记-整理):Serial Old 、Parallel Old
    单线程:Serial、Serial Old
    多线程: Parallel Scavenge、Parallel Old、ParNew、CMS(标记清除)
    G1:

  3. 讲一下 CMS 垃圾收集器的四个步骤。CMS 有什么缺点?
    初始标记: 暂停所有的其他线程,并记录下直接与 root 相连的对象,速度很快 ;
    并发标记: 同时开启 GC 和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,所以 GC 线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。
    重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短
    并发清除: 开启用户线程,同时 GC 线程开始对未标记的区域做清扫。
    缺点: 对 CPU 资源敏感; 无法处理浮动垃圾, 存在空间碎片化

  4. G1 垃圾收集器的步骤。有什么缺点?
    G1(分区Region):首先
    缺点: G1 无论是在垃圾收集产生的内存占用还是程序运行时的额外执行负载都要比CMS要高

下一篇:JVM_日志_内存分配与回收策略_JVM学习(二)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值