架构师训练营第九周作业
请简述 JVM 垃圾回收原理
JVM垃圾回收就是将JVM堆中的已经不再被使用的对象清理掉,释放宝贵的内存资源。
这就要从JVM的原理说起,JVM启动一个进程,通过类加载器把用户指定的类文件加载到进程的运行期区,其中的代码和类的静态变量都是放在方法区,然后启动一个主线程去执行代码的入口(Main方法),线程会被分配对应的Java栈和程序计数器,对于代码的局部变量:参数、方法体中定义的局部变量都保存在Java栈中,以栈帧的方式放在栈顶,如果是基本类型,这个变量本身就保存了值,如果是复杂类型,则会在进程堆中分配内存并保存相应的值。程序计数器用来记录每个线程的代码执行到了第几行。此外,对于类的成员非静态成员变量,则是保存在进程堆里被所有线程共享的。
因此大量占用内存的是保存复杂类型的堆空间,方法调用结束相应的栈帧会出栈,其对应的局部变量所占用的堆空间就不再使用了,同样的,对应类,离开了使用场景,其成员变量所占用的堆空间也不再使用了。而内存空间是小且宝贵的,因为JVM需要一套垃圾回收机制来识别哪些堆空间不再被程序使用,并进行清理和回收。
具体过程是:从线程栈中的局部变量,或者是方法的静态变量,又或者类的成员变量(这点老师没有讲,但是我觉得是需要的)出发,将这些变量引用的对象进行标记,然后看这些被标记的对象是否引用了其他对象,继续进行标记,所有被标记过的对象都是被使用的对象,而那些没有被标记的对象就是可回收的垃圾对象了。
标记完成后,JVM使用三种方法来回收内存:清理,将垃圾对象占据的内存清理掉,其实JVM并不会真的将这些垃圾内存进行清理,只是将他们占用的空间标记为空闲,记录在一个空闲列表里,当应用程序需要创建对象的时候,从空闲列表里找一段空闲内存分配给这个新对象;压缩:从堆空间的头部开始,将存活的对象拷贝放在一段连续的内存空间中,那么其余的你空间就是空闲空间,也就是搬迁整理;复制:将堆空间分成两部分,只在其中一部分创建对象,当这个部分用完的时候,将标记过的可用对象复制到另一个空间中。
JVM进行标记时,需要暂停所有正在执行的进程线程,否则一边标记一边又在创建,就没法完成了;常用有串行回收器,单核时代使用;并行回收器,多核时代使用;并发回收器CMS和GI回收器。
设计一个秒杀系统,主要的挑战和问题有哪些?核心的架构方案或者思路有哪些?
主要的挑战在于:集中的,瞬间的高并发请求,成千上万的人在同一个时间点向服务器的单条数据发起访问,上千的并发数,会导致服务器失去响应和崩溃;大量的网络请求会耗尽服务器带宽;专门的秒杀工具会主动多次刷新页面,并且可能会绕过秒杀页面直接进入下单页面。
核心的思路是:为秒杀活动专门开发新的模块,而不是再原有程序上进行改造,时间成本和人力成本不可控;新开发的模块全面采用集群和静态化,提升服务器带宽并采用CDN分流流量。设置阀门只放最前面的一部分人进入秒杀系统;简化流程,砍掉不重要的分支流程,如下单页面的所有数据库查询。
三道阀门的设计:首先能够进入秒杀商品详情页的有1000人,超过就直接跳转到秒杀结束页面;然后能够进入下单页面的有100人,超过就直接跳转到秒杀结束页面;能够进到支付系统的有56人,超过则跳转到秒杀结束页面。已经参加过秒杀的则直接跳转到秒杀结束页面。通过这三级控制,已经把访问并发数控制到服务器能承受的并发数范围之内了。
为了预防秒杀工具,秒杀的入口在时间开始之前是没有的,前两秒由静态页面的JS脚本生成入口,方可进入秒杀,且URL是随机生成。进入下单页必须带上随机生成的令牌作为URL参数,以供服务器校验是否是从上一级页面正常跳转过来的,比如通过商品详情页进入的而不是绕进来的。在商品详情页和下单页都需要实现阀门控制。
评论