写点什么

架构师训练营第九周作业

用户头像
Geek_2dfa9a
关注
发布于: 2020 年 08 月 05 日

JVM垃圾回收原理

1.如何标记回收对象

引用计数法和可达性算法

  • 引用计数法是给每个对象分配一个计数器,每当有一个引用赋值,就给被引用的对象计数器+1,如果对应的引用赋值其他对象,则计数器的引用-1,当计数器为0时则表示对象不可达,可以回收。但是引用计数法有局限,比如说循环引用,后果是循环引用的对象无法回收,内存泄露。

public class RefCount {
private RefCount ref;
public static void main(String[] args) {
RefCount a = new RefCount();
RefCount b = new RefCount();
a.ref = b;
b.ref = a;
a = null;
b = null;
}
}
  • 可达性算法是从一组包含GCRoots的集合开始探索所有呗引用到的对象,再将这些对象加入集合,继续探索,这个过程叫做标记,最后没有被标记到的对象就可以被回收。上面提到的GCRoot有几种:Java 方法栈桢中的局部变量;已加载类的静态变量;JNI handles;已启动且未停止的 Java 线程。

2.垃圾回收算法

垃圾回收算法分为三种:

  1. 标记-清除,将可以回收的对象内存地址记录下来,下次创建新对象时直接在这些地址上分配,这样做有两个缺点:回收对象的不连续性导致的内存碎片,另一个是分配效率较低,因为需要遍历整段内存来查找可用内存。

  2. 标记-整理,将存活的对象挪到内存一端,这样解决了清除的两个缺点,不会有内存碎片而且只需记录未分配内存的地址,直接挪动指针就可以分配内存,但是会有要挪动对象导致的效率问题。

  3. 复制,复制算法将内存一分为二:from和to,先在from上分配对象,垃圾回收时把from存活的对象复制到to上然后把from指针指向to,to指针指向from,这种算法带来的问题是内存使用效率低,总有50%的内存无法使用。

3.分带回收

jvm堆分为新生代和老年代,根据一些统计和猜测大部分新生代对象的存活时间都很短因此新生代发生MinorGC一般采用标记复制算法,新生代有三块区域:eden,suvivor from,suvivor to,新对象分配在eden上会采用一种叫Tlab的技术,给每个线程分配一段空间来避免分配空间的同步导致的效率地下,

在eden空间不足时会发生一次MinorGC,将suvivor from的存活对象和eden的存活对象复制到suvivor to,需要注意的是suvivor from里面的jvm会记录对象复制了几次,次数越多说明对象存活时间越久,当该参数到达15(可通过虚拟机参数调整)时会把对象晋升到老年代,此外还有suvivor占用达到50%时也会把较高复制次数的对象复制到老年代。

4.四种垃圾回收器

新生代一般采用Serial,Parallel Scavenge 和 Parallel New,这三种都是复制算法,Serial是单线程,Parallel New是多线程,Parallel Scavenge和Parallel New类似,但是更注重吞吐量,此外,Parallel Scavenge 不能与 CMS 一起使用。老年代一般采用Serial Old 和 Parallel Old,以及 CMS。Serial Old 和 Parallel Old都采用标记-整理算法,前者是单线程的后者是多线程的。而CMS采用标记清除算法,并且是并发的,除了少数几个操作需要 Stop-the-world 之外,它可以在应用程序运行过程中进行垃圾回收。在并发收集失败的情况下,Java 虚拟机会使用其他两个垃圾回收器进行一次垃圾回收。



秒杀系统的问题和挑战

1.对现有业务的冲击

如果秒杀系统和现有业务系统没做隔离的话,秒杀活动进行期间很容易影响现有系统,一个好的解决思路是在业务的允许下隔离分开部署,如果没法隔离的话也可以考虑限流(比如通过计数器)限制访问人数,减少秒杀流程环节(比如下单支付分离)来解决。

2.高并发下系统和数据库的负载

高并发下很容易增大应用服务器和数据库的负载,一个解决方案是通过直接把数据写进静态页面,这样不会请求服务和数据库。

3.商品图片的带宽压力

如果图片容量很大,高并发下也会造成带宽压力,可以考虑临时升级带宽或者使用CDN服务器来解决。

4.直接下单

动态生成下单链接,避免秒杀活动没开始用户提前进入下单页面等待。



用户头像

Geek_2dfa9a

关注

还未添加个人签名 2019.02.18 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营第九周作业