JVM 垃圾回收原理与秒杀系统

用户头像
ashuai1106
关注
发布于: 2020 年 08 月 05 日
JVM垃圾回收原理与秒杀系统



一、请简述 JVM 垃圾回收原理。



一、JVM 垃圾回收原理

从两个方面简述,jvm内存模型和jvm回收算法,前面是问题的根,后面是解决问题的方案。

1、JVM内存模型

  • pc寄存器:当前线程所执行的字节码的行号指示器

  • 虚拟机栈:用于存储局部变量表、操作栈、动态链接、方法出口等信息

  • 本地方法栈:局部变量

  • 堆:class对象、数组,所有线程共享,不是所有的对象都在堆上分配,比如JIT优化-逃逸分析

  • 方法区:运行时数据:静态变量、静态方法、常量池、类的代码

Java虚拟机运行时数据区域主要包含了PC寄存器(程序计数器)、Java虚拟机栈、本地方法栈、Java堆、方法区以及运行时常量池。

在JVM运行时内存区域中,PC寄存器、虚拟机栈和本地方法栈是线程独享的。

而Java堆、方法区是线程共享的。但是值得注意的是,Java堆其实还未每一个线程单独分配了一块TLAB空间,这部分空间在分配时是线程独享的,在使用时是线程共享的。



JVM中存在着大量的声明短暂的对象,还有一些生命周期比较长的对象。为了对他们采用不同的收集策略,采用了分代收集算法,所以HotSpot虚拟机把的根据对象的年龄不同,把堆分位新生代、老年代和永久代(8之后为元空间)。

对于一个普通的Java对象的创建,大致过程如下:

1、虚拟机遇到new指令,到常量池定位到这个类的符号引用。 

2、检查符号引用代表的类是否被加载、解析、初始化过。 

3、虚拟机为对象分配内存。 

4、虚拟机将分配到的内存空间都初始化为零值。 

5、虚拟机对对象进行必要的设置。 

6、执行方法,成员变量进行初始化。



2、垃圾回收算法

垃圾回收的依据

  • 对象存活判断:引用计数(根据对象的引用计数,新增+1,释放-1,0可以回收,无法解决对象互相循环引用的问题)和可达性分析(GC roots向下搜索,查看引用链,当一个对象到GC roots没有引用链则不可用,为不可达对象)

  • GC算法:标记 -清除算法、复制算法、标记-压缩算法、分代收集算法

  • 垃圾回收器



垃圾回收器可以分为四类,前三种都基于标记-清除(复制)算法:

  1. 标记:在需要回收的内存空间中,扫描并标记哪些区块是在使用的,哪些已经失效。视需要扫描的内存空间大小而定,这个过程可能相对会比较耗时。

  2. 清除:将被标记为未使用的内存区块对应的对象引用删除。

  3. 压缩:如果使用中的内存区块碎片化,需要把它们挪动到一起组成连续空间,以提高内存空间分配效率。相当于把使用中的内存区块分布区域“压缩”到了小块连续区域。

分代回收

标记内存使用情况需要扫描整个内存空间。如果内存空间很大,这个过程会相当耗时。另一方面,大部分对象的生命周期都非常短,创建后不久就失效了。基于这两点,JVM将内存空间又进一步按照对象存活时间划分成了代际区块。



  并行算法是用多线程进行垃圾回收,回收期间会暂停程序的执行,而并发算法,也是多线程回收,但期间不停止应用执行。所以,并发算法适用于交互性高的一些程序。经过观察,并发算法会减少年轻代的大小,其实就是使用了一个大的年老代,这反过来跟并行算法相比吞吐量相对较低。



  垃圾回收动作何时执行?下面的流程进行说明



  • 新创建的对象放在Eden区(年轻代)

  • 当年轻代内存满时,会引发一次普通GC(minorGC),该GC仅回收年轻代,仍被引用的对象被复制到S0,未被引用的对象留在Eden区,随后被全部清空。需要强调的时,年轻代满是指Eden代满,Survivor满不会引发GC。当下一次minor GC触发时,Eden区及S0区的有被引用对象都被复制到S1区,随后Eden和S0被清空释放。当Eden区再次触发minorGC时,由于S1已经在上次GC后装载了幸存对象,而S0被清空。所有这次将反过来,将Eden区和S1的有引用对象复制到S0,然后清空Eden和S1区。在经历了数次这样的GC过程后,某些幸存对象已经足够成熟,将被复制到老年区,而还不够成熟的对象将继续在S0和S1之间复制,经受历练。

  • 当年老代满时会引发Full GC,Full GC将会同时回收年轻代、年老代

  • 当永久代满时也会引发Full GC,会导致Class、Method元信息的卸载



垃圾回收器

根据这几个算法在不同的阶段实现的垃圾回收器如下:

  • 串行回收器:早期单核 用单线程效率最高

  • 并行回收器:多核,若服务器cpu内核低于3,实际效果与串行回收器没有差别。

  • 并发回收器CMS:并发标记清理,获取最短回收停顿时间为目标的收集器,可能牺牲一定的吞吐量

  • G1回收器:针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征,从Java7开始,作为CMS的替代品被引入。它是并行的,多线程,低暂停时间,增量压缩式的回收器。



  JVM会根据机器的硬件配置对每个内存代选择适合的回收算法,比如,如果机器多于1个核,会对年轻代选择并行算法,关于选择细节请参考JVM调优文档。



OOM异常

  另一个问题是,何时会抛出OutOfMemoryException,并不是内存被耗空的时候才抛出

  • JVM98%的时间都花费在内存回收

  • 每次回收的内存小于2%

  满足这两个条件将触发OutOfMemoryException,这将会留给系统一个微小的间隙以做一些Down之前的操作,比如手动打印Heap Dump。

Jvm参数优化目标:

  • GC的时间足够的小

  • GC的次数足够的少

  • 发生Full GC的周期足够的长

为了达到上面的目的,可以优化的点:



1、减少使用全局变量和大对象;

2、调整新生代的大小到最合适;

3、设置老年代的大小为最合适;

4、选择合适的GC收集器;



3、调优命令

  • jps,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。

  • jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。

  • jmap,JVM Memory Map命令用于生成heap dump文件

  • jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看

  • jstack,用于生成java虚拟机当前时刻的线程快照。

  • jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。



二. 设计一个秒杀系统, 主要的挑战和问题有哪些?



1、秒杀场景特点

  • 定时开始,秒杀时大量用户会在同一时间,抢购同一商品,网站瞬时流量激增。

  • 库存有限,秒杀下单数量远远大于库存数量,只有少部分用户能够秒杀成功。

  • 操作可靠,秒杀业务流程比较简单,一般就是下订单减库存。库存就是用户争夺的“资源”,实际被消费的“资源”不能超过计划要售出的“资源”,也就是不能被“超卖”。



2、秒杀的场景特点带来的挑战和问题

由于短时间内的高并发,会产生大量的请求,对网络和服务资源都有竞争性,不能和其它业务糅合到一起,也不是改改原来的就可以了,需要由顶而下做资源隔离(重新搭建秒杀系统)。需要对某一点都要进行资源扩容和优化,同时进一步做限流

  • 宽带资源

  • 服务器资源(style、图片、静态资源等)

  • 交易服务器

3、解决问题的步骤和方案

  1. 通过商业需求,分析并发量等

  2. 分析目前的性能现状,需要做什么

  3. 系统隔离:业务隔离、技术隔离、数据库隔离

  4. 性能压测:任何系统没有测试都是没有保证的。

  5. 突发状况响应:对一些不重要的功能或系统熔断降级等,为秒杀让路。





https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

用户头像

ashuai1106

关注

还未添加个人签名 2017.10.20 加入

还未添加个人简介

评论

发布
暂无评论
JVM垃圾回收原理与秒杀系统