写点什么

架构师训练营 1 期第 9 周:性能优化(三)- 作业

用户头像
piercebn
关注
发布于: 2020 年 11 月 22 日

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

JVM 垃圾回收就是将 JVM 堆中的已经不再被使用的对象清理掉,释放宝贵的内存资源。

垃圾对象识别

JVM 通过一种可达性分析算法进行垃圾对象的识别,具体过程是:从线程栈帧中的局部变量,或者是方法区的静态变量出发,将这些变量引用的对象进行标记,然后看这些被 标记的对象是否引用了其他对象,继续进行标记,所有被标记过的对象都是被使用的对象,而那些没有被标记的对象就是可回收的垃圾对象了。

垃圾对象回收

进行完标记以后,JVM 就会对垃圾对象占用的内存进行回收,回收主要有三种方法

  • 清理:将垃圾对象占据的内存清理掉,其实 JVM 并不会真的将这些垃圾内存进行清理,而是将这些垃圾对象占用的内存空间标记为空闲,记录在一个空闲列表里,当应用程序需要创建新对象的时候,就从空闲列表中找一段空闲内存分配给这个新对象。

  • 压缩:从堆空间的头部开始,将存活的对象拷贝放在一段连续的内存空间中,那么其余的空间就是连续的空闲空间。

  • 复制:将堆空间分成两部分,只在其中一部分创建对象,当这个部分空间用完的时候,将标记过的可用对象复制到另一个空间中。

  • 在使用中,更多的是使用压缩或复制的方法进行垃圾回收。

JVM 分代垃圾回收策略

分代垃圾回收是把内存空间分成两个代,一个叫做新生代,一个叫做老年代。

  • 在实际中发现 Java 中的对象大部分的生存时间是很短暂的,比如在方法中 new 一个新对象,方法执行完后退出方法的时候,栈帧出栈,引用被销毁了,对象就失去引用了,变成垃圾对象,就可以回收了,仅仅是一个方法内部的生存时间。针对这些短暂生存时间的对象,可否放在一个较小的区域里去,并快速的对较小区域里的对象进行回收,这样回收的范围比较小,扫描的对象少,回收速度更快。

  • 基于这种思路把 Java 的堆内存空间分成了两块,一块是新生代,一块是老年代,对象创建的时候在新生代中创建,回收的时候先在新生代中回收,如果经过一段时间,对象还没有被回收,说明这个对象的生命周期比较长,再把它复制到老年代。

新生代中分了三个区域,一个 Eden 区,一个 From 区,一个 To 区。

  • 对象刚刚创建的时候是在 Eden 区创建,当 Eden 区满的时候,就要进行垃圾回收了,Eden 区的大部分对象在回收的时候都已经变成垃圾对象了,我们就可以把这些垃圾对象回收掉。

  • 具体的回收过程用的是复制算法,我们先进行对象标记,把通过标记在用的对象拷贝到 From 区,剩下的就是一块完全空白的 Eden 区,垃圾回收做完后,程序代码执行时还会继续在 Eden 区创建对象,Eden 区满后,会再次进行对象标记并把可用对象拷贝到 From 区,当 From 区满后,会把 From 区的对象拷贝到 To 区,这样 From 区也空了,可以继续和 Eden 区配合进行垃圾回收操作。在回收的时候,会同时遍历 Eden 区和 To 区的可用对象,并将其拷贝到 From 区,这样三个区域配合反复进行垃圾回收操作。

老年代就一个区,空间相对比新生代更大。

  • 当进行几次回收操作以后,如何还有对象没有被回收,说明该对象生命周期会比较长,就不会在新生代进行来回拷贝了,会把这个对象拷贝到老年代。拷贝一段时间后老年代的对象也满了,会对老年代也进行一次垃圾回收。

垃圾回收过程

  • 垃圾回收分为两种,一种是对新生代进行垃圾回收,一种是对老年代进行垃圾回收,当对老年代垃圾回收的时候,对新生代也要进行垃圾回收,所以对垃圾回收可以分成 Young GC(新生代的垃圾回收)和 Full GC(全量的垃圾回收,新生代和老年代一起垃圾回收)两种垃圾回收过程

JVM 垃圾回收器算法

具体在进行垃圾回收,在标记垃圾对象以及回收垃圾对象空间的时候,垃圾回收程序(垃圾回收器)在 JVM 不同的版本中有很多中,分别采用不同的算法实现

  • 典型的有串行回收器、并行回收器、并发回收器、G1 回收器

  • 最早的是串行回收器,应用程序多线程在执行,当空间不足,需要进行垃圾回收的时候,所有的线程都停止运行(叫做 stop the world),启动一个垃圾回收线程进行对象标记和垃圾空间的清理回收,垃圾回收完了以后再启动应用线程,由于垃圾回收线程只有一个,所以叫串行垃圾回收器。

  • 并行回收器,当出现多核 CPU 以后,可以针对 CPU 的核数同时启动多个垃圾回收线程,并行的进行垃圾回收,依然采用 stop the world 方式,所有用户线程被终止。

  • 并发回收器,采用 stop the world 方式,所有用户线程被终止,对用户线程影响比较大,影响响应时间,为了避免垃圾回收对用户线程的影响,提高用户线程的执行效率,减少响应时间,产生了并发垃圾回收器,把整个的垃圾回收过程分得更加详细,分成初始标记、并发标记、重标记和并发清理 4 个阶段,初始标记时需要 stop the world,时间会很短,然后进入并发标记阶段,垃圾回收线程和用户线程并发执行,不会对用户线程造成较大的影响,并发标记完了以后,由于在标记过程中又有新的对象产生,前面标记过得可能会不准确,所以需要重新进行标记,在这个过程中,为了保证不会有对象被遗漏,重标记的时候还需要 stop the world,只有垃圾回收线程进行标记,所有对象标记完后,然后进行清理在清理的时候,清理的垃圾回收线程和用户线程也是并发的执行的,所以整个过程中,大部分的时间垃圾回收线程和用户线程是并发执行的,stop the world 的时间就会比较少,对于用户线程的影响比较小,对响应时间的影响也比较小。对 web 应用请求,以前主要使用 CMS 并发回收器。

  • G1 回收器,对比较新的版本,更多的使用 G1 垃圾回收器,它把整个的内存空间分成了更小的区域,默认情况下分成 2000 个区域,每个区域管理较小的内存空间,垃圾回收标记处理速度更快,这些小块也有自己的角色,包括 Eden 区,From 区 To 区(Survivor),老年区(Old),大内存区(Humongous),进行垃圾回收的时候针对具体的区域进行回收,动态的去调整回收的过程,对用户程序影响也比较小,占用的资源也比较小,可以管理的内存空间更大,这里主要使用的是 Max 最大的 GC 暂停时间去控制,G1 垃圾回收器会根据期望的指定时间,动态的调整回收的策略,以达到期望的 stop the world 的时间。

二、设计一个秒杀系统,主要的挑战和问题有哪些?核心的架构方案或者思路有哪些?

技术挑战 

瞬间高并发

  • 8000 并发:预估秒杀在线人数可达 8000 人 。

  • 风险:带宽耗尽。

  • 服务器:崩溃,可以理解成自己给自己准备的 D.D.O.S 攻击。 

秒杀器

  • 第一种:秒杀前不断刷新秒杀页面,直到秒杀开始,抢着下单。

  • 第二种:跳过秒杀页面,直接进入下单页面,下单。

架构方案设计原则

静态化

  • 采用 JS 自动更新技术将动态页面转化为静态页面 

并发控制,防秒杀器

  • 设置阀门,只放最前面的一部分人进入秒杀系统 

简化流程

  • 砍掉不重要的分支流程,如下单页面的所有数据库查询

  • 以下单成功作为秒杀成功标志。支付流程只要在 1 天内完成即可。 

前端优化 

  • 采用 YSLOW 原则提升页面响应速度


发布于: 2020 年 11 月 22 日阅读数: 25
用户头像

piercebn

关注

还未添加个人签名 2019.07.24 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营 1 期第 9 周:性能优化(三)- 作业