《别看了,你学不会的》——JVM(二)

JVM

局部变量表的槽位复用
    public void Gc4() {
        {
            int[] a = {1, 2, 3};
            System.out.println(a);
        }
        int b = 100;
        System.gc();
    }

在这里插入图片描述
从中可以发现,b复用了a的槽位,也就是index。那么为什么b可以复用a的槽位呢?仅仅只因为它是个b吗……

当然不是这样!

那是因为a是局部变量,当局部变量执行完毕后,局部变量的内存空间就会被释放,所以b也就能使用a的index了

栈上分配

在给对象分配内存空间时,首先会进行栈上分配,如果栈上分配不行,才会进行TLAB分配,TLAB分配不行的话,就会进行堆上分配,堆上分配分两种,如果是小对象的话会在年轻代分配,如果是大对象的话会在老年代分配

针对小而多的对象,会优先采用栈上分配。栈是线程私有的,所以线程私有的对象才能进行栈上分配——逃逸分析

如果一个对象满足栈上分配的话,需要先打散然后放到栈中——标量替换

逃逸分析

分析对象是不是逃出了线程私有

标量替换

Java中的一些基本类型

聚合量:可以被进一步拆解

TLAB分配
  • Thread Local Allocation Buffer:线程本地分配缓冲区
  • TLAB空间很小,放在Eden区,占1%的空间
主要的垃圾回收算法

在这里插入图片描述

引用计数法

对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,则对象A就不可能再被使用

但引用计数器有两个严重问题

  1. 无法处理循环引用的情况在这里插入图片描述
  2. 引用计数器要求再每次引用产生和消除的时候,需要伴随一个加减法操作,对系统性能会有一定的影响

因此JVM并未选择此算法作为垃圾回收算法

标记清除法
  • 标记清除算法是现代垃圾回收算法的思想基础
  • 分为两个阶段:标记阶段和清除阶段
  • 标记清除算法产生最大的问题就是清除之后的空间碎片

根节点出发,就能知道哪些对象是活跃的,哪些对象是死亡的,引用的对象就标记;把没有标记的对象清除掉

复制算法

将原有的内存空间分为2块,每次只使用其中一块内存,例如:A内存,GC时将存活的对象复制到B内存中。然后清除掉A内存所有对象。开始使用B内存

复制算法没有内存碎片,并且如果垃圾对象很多,那么这种算法效率很高。但是它的缺点是系统内存只能使用1/2

复制算法在JVM中的使用

因为新生代90%的对象都是临时对象,所以在新生代串行GC中,使用了复制算法

老年代中不使用复制算法,因为老年代可能只有10%的对象需要回收,如果使用复制算法,需要复制的对象很多,会导致垃圾回收的效率非常低

标记压缩法

标记压缩算法是一种老年代的回收算法
它首先标记存活的对象,然后将所有存活的对象压缩到内存的一端,然后再清除所有存活对象之外的空间

标记压缩算法的效率不如复制算法,但是标记压缩算法用于老年代,而复制算法用于新生代
分代算法

堆空间中分为新生代老年代,为了提高垃圾回收的效率,不同的代中使用不同的垃圾回收算法

分区算法

将堆空间分为不同的小区间,对每个小区间进行回收,而不是每次都回收整个堆空间,这样能提高回收的的效率,当堆空间大时,执行GC会很费时

JVM垃圾回收器
串行回收器

串行回收器只使用单线程进行GC,而且是独占式GC

串行收集器是JVM Client模式下默认的垃圾回收器,所有应用都要等待GC执行完毕,才可以继续执行

JVM参数作用
-XX:SurvivorRatio设置Eden区与survivor区比例
-XX:PretenureSizeThreshold设置大对象直接进入老年代的阈值
-XX:MaxTenuringThreshold设置对象进入老年代的年龄阈值

启用指定的回收器

JVM参数新生代老年代
-XX:+UseSerialGC串行回收器
串行回收器
-XX:+UseParNewGCParNew串行回收器
-XX:+UseParallelGCParalllelGC串行回收器
并行回收器

将串行回收器多线程化,与串行回收器有相同的回收策略、算法、参数

JVM参数新生代老年代
-XX:+UseParNewGCParNew串行回收器
-XX:+UseConcMarkSweepGCParNewCMS
-XX:+UseParallelGCParallelGC串行回收器
-XX:+UseParallelOldGCParallelGCParallelGC

并行回收器JVM参数

收集器JVM参数作用
ParNew-XX:ParallelGCThreads指定GC时工作的线程数
ParallelGC-XX:MaxGCPauseMillis最大的垃圾收集暂停时间
-XX:GCTimeRatio设置垃圾收集吞吐量
-XX:+UseAdaptiveSisePolicy打开自适应垃圾收集策略
ParallelOldGC-XX:+ParallelGCThreads指定GC时工作的线程数量
CMS-XX:-CMSPrecleaningEnabled禁用预清理操作
-XX:ConcGCThreads设置并发线程数量
-XX:PartallelCMSThreads设置并发线程数量
-XX:CMSInitiatingOccupancyFraction当老年代空间使用量达到某百分比时,会执行CMS。默认为68
-XX:+CMSCompactAtFullConllectionGC后,进行一次碎片整理
-XX:CMSFullGCsBeforeCompaction指定执行多少次GC后,进行一次碎片整理
G1点GC收集过程

G1全称Garbage First Garbage Collector,优先回收垃圾比例最高的区域
G1收集器将堆划分为多个区域,每次收集部分区域来减少GC产生的停顿时间

新生代GC

当Eden区被占满后,新生代GC就会启动;回收后,Eden区会被清空,survivor会保留一部分数据;部分新生代对象会晋升到老年代

混合回收

第一阶段新生代GC——>第二阶段并发标记周期——>第三阶段混合回收

由于触发年轻代GC,Eden区域会被清空;被标记的年轻代和老年代都会被回收;垃圾比例高的会被清理,剩余存活对象会被移动其他区域,减少内存碎片

JVM常用参数

参数作用
-Xms128m设置初始化堆内存为128M
-Xmx512m设置最大堆内存为512M
-Xmn160m设置新生代大小为-Xmn160M(堆空间1/4~1/3)
-Xss128m设置最大栈内存为128M
-XX:SurvivorRatio设置新生代eden区与from/to空间的比例关系
-XX:PermSize=64M设置初始永久区64M
-XX:MaxPermSize=128M设置最大永久区128M
-XX:MaxMetaspaceSize设置元数据区大小(JDK1.8 取代永久区)
-XX:+DoEscapeAnalysis启用逃逸分析(Server模式)
-XX:+EliminateAllocations开启标量替换(默认开启)
-XX:+TraceClassLoading跟踪类的加载
-XX:+TraceClassUnloading跟踪类的卸载
-Xloggc:gc.log将gc日志信息打印到gc.log文件中
-XX:+PrintGC打印GC日志
-XX:+PrintGCDetails打印GC详细日志
-XX:+PrintGCTimeStamps输出GC发生的时间
-XX:+PrintGCApplicationStoppedTimeGC产生停顿的时间
-XX:+PrintGCApplicationConcurrentTime应用执行的时间
-XX:+PrintHeapAtGC在GC发生前后,打印堆栈日志
-XX:+PrintReferenceGC打印对象引用信息
-XX:+PrintVMOptions打印虚拟机参数
-XX:+PrintCommandLineFlags打印虚拟机显式和隐式参数
-XX:+PrintFlagsFinal打印所有系统参数
-XX:+PrintTLAB打印TLAB相关分配信息
-XX:+UseTLAB打开TLAB
-XX:TLABSize设置TLAB大小
-XX:+ResizeTLAB自动调整TLAB大小
-XX:+DisableExplicitGC禁用显示GC (System.gc())
-XX:+ExplicitGCInvokesConcurrent使用并发方式处理显式GC
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值