架构师训练营 第九周课程
请简述 JVM 垃圾回收原理。
- JVM 垃圾回收是指将堆中不再使用的对象回收,该回收机制通过可达性算法识别垃圾回收对象,其具体的操作算法如下 
- 从线程栈帧的局部变量,或者方法的静态变量出发,把这些变量引用的对象进行标识 
- 看该对象是否引用了其它对象,如果有,则将其它对象也进行标记 
- 以此类推,将所有变量遍历完毕 
- 在堆中,没有被标记的对象就似乎可以被回收的对象 
- JVM 垃圾回收过程,涉及到如下三个步骤 
- 清理,标记不用的对象空间(并不会真的删除,知识标明该内存空间可用) 
- 压缩,将存活的对象拷贝到一段连续的内存空间中,目的是尽可能保证可用空间是连续的,因为类似数组之类的存储结构,是需要连续的空间来存储 
- 复制,对空间分为两部分 A 和 B,在 A 中新创建对象,当 A 中空间用完了,则将还生存的对象拷贝到空间 B 中,目的是将存活时间较长的对象移动到额外区域 
- 垃圾回收思想 
- 大部分时候 java 中对象的生存周期都是很短的,因此可以开辟一块较小的区域(新生区),用来存放新初始化的对象,因为空间较小,那么扫描的时间成本也会较低。如果经过一段时间,新生区的对象还没有回收,则可以移动到另外一块区域(老年代) 
- 新生代区域分为三块,eden 区,from 区,以及 to 区。新创建的对象都是在 eden 区,当 eden 区满了,垃圾回收开始工作,将 eden 区垃圾回收,同时将还存活的对象迁移到 from 区或者 to 区。如果 from 区满了则迁移到 to 区,from 区清空。下次遍历就是便利 eden 区和 to 区,将不用对象迁移到 from 区。如果 from 区也满了,则将对象迁移到老年代。当老年代空间也满了,再对老年代区间垃圾回收 
- 不同时期的 JVM 版本,对垃圾回收的实现也不同 
- 早期是串行回收器,回收线程会阻塞当前用户执行的线程,称为 stop-the-world 
- 下一步演化为并行的垃圾回收期,充分利用了 cpu 多核心。但垃圾回收时候,同样所有的回收线程也阻塞了用户线程,也是 stop-the-world 
- 再进一步演化成并发回收器 CMS,该回收器分为四个部分 
- 初始化标记,会 stop-the-world 
- 并发标记,跟用户线程并行 
- 重标记,多线程标记,stop-the-world,因为之前标记的时候,可能有用户线程新产生了,为了防止遗漏,需要阻塞所有用户线程,进行再次标记 
- 并发清理(跟用户线程并行) 
- 再一步演化为 G1 垃圾回收器 
- G1 将内存分为更细的块(比如说切分成 2000 个小块,这些小块同样有 eden,from,to,老年区之类) 
- 通过配置-xx:MaxGCPauseMillis,可以控制老年区的回收时间,进而控制 stop-the-world 时间 
- 设计一个秒杀系统,主要的挑战和问题有哪些?核心的架构方案或者思路有哪些? 
- 主要挑战 
- 大量的用户短时间并发请求,对服务器造成极大压力 
- 当并发量是平时系统负载的几百倍时候,购买硬件扩充系统成本会非常高 
- 架构思路 
- 如果改造旧系统成本太高,不妨做一个新系统应对秒杀 
- 如果短时间大并发的请求无法处理,根据秒杀的业务特性,只有少数用户能下单,不妨设计阀门机制,将用户请求直接拦截在下单系统外 
- 尽可能将动态资源改为静态资源,使用 CDN 加速 
- 减少对外部系统的访问频率,例如 DB 
- 减少用户 http 请求次数 
- 使用空白的 js 文件,这个空白 js 文件不缓存,放置到服务器中,因为是空文件,所以即使用户请求,也不会占用太多带宽,等到秒杀开始的时候,在该文件中填充商品 id 和随机生成的下单 url 地址,防止用户作弊。 
版权声明: 本文为 InfoQ 作者【文江】的原创文章。
原文链接:【http://xie.infoq.cn/article/76f8eb53e18daeab88da1d783】。未经作者许可,禁止转载。












 
    
评论