架构师课程第九周 作业

用户头像
杉松壁
关注
发布于: 2020 年 08 月 02 日
一、请简述JVM垃圾回收原理

JVM的垃圾回收就是将JVM堆中已经不再被使用的对象清理掉。JVM通过一种可达性分析算法进行垃圾对象的识别,具体过程是:从线程栈帧中的局部变量,或者是方法区的静态变量出发,将这些变量引用的对象进行标记,然后看这些被标记的对象是否引用了其他对象,继续进行标记,所有被标记过的对象都是被使用的对象,而那些没有被标记的对象就是可回收的垃圾对象了。进行完标记以后,JVM就会对垃圾对象占用的内存进行回收,回收主要有三种方法:清理、压缩、复制。清理即是将垃圾空间标记为空间,记录在一个空闲内存列表中,当应用程序需要创建对象的时候,就从空间列表中找一块内存分配给这个新对象。压缩是从堆的头部开始,将存活的对象拷贝到一段连续的内存空间中,那么其余的空间就是连续的空闲空间。复制是将堆空间分成两个部分,只在其中一部分创建对象,当这个部分的空间用完的时候,将标记过的可用对象复制到另一个空间中。JVM使用分代垃圾回收。将堆空间分为老年代、新生代,其中新生代又分为eden区、from(Survivor1)区、to(Survivor2)区,创建对象的时候从eden区寻找内存,当eden区内存不足时启动垃圾回收,将标记过的对象拷贝到from区,继续在eden区创建对象。当eden区再次满了的时候,将eden区和from区进行垃圾标记,将标记过的对象拷贝到to区。当eden区再次满的时候,将eden区和to区做垃圾标记,将标记的对象拷贝到from区,以此类推。当一个对象经过多次标记之后仍然存在的时候可以将该对象拷贝到老年代中。当所有内存都不足的时候,启动FullGC,对所有内存进行标记回收。默认的,新生代( Young )与老年代( Old )的比例的值为1:2 (该值可以通过参数 –XX:NewRatio来指定),即:新生代( Young ) = 1/3的堆空间大小。老年代( Old ) = 2/3的堆空间大小。其中新生代中,默认的,Eden : from : to = 8 : 1 : 1 (可以通过参数 –XX:SurvivorRatio来设定),即:Eden = 8/10的新生代空间大小,from = to = 1/10的新生代空间大小。JVM每次只会使用Eden和其中的一块Survivor区域来为对象服务,所以无论什么时候,总是有一块Survivor区域是空闲着的。因此,新生代实际可用的内存空间为9/10 (即90% )的新生代空间。JVM垃圾回收算法有:串行回收器、并行回收器、并发回收器CMS、G1回收器,Java8之后默认使用G1回收器,如果想使用CMS回收器,可以使用参数-XX:UseConcMarkSweepGC。

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

 主要问题:

  1. 瞬时并发高;

  2. 相对来说秒杀的产品内容少。

架构方案与思路:

  1. 使用中间件消息削峰填谷;

  2. 在网络入口,代理等地方消减流量;

  3. 图片以及静态内容使用CDN;

  4. 使用浏览器缓存;

  5. 独立部署秒杀系统。

三、总结

本周的主要内容有:JVM原理解析、Java代码优化、秒杀系统案例与宅米网系统案例。

JVM(Java Virtual Machine)是Java程序运行虚拟机,Java代码经过编译器编译成Java字节码文件,就可以放到JVM虚拟机上执行,而且就算平台发生了变化,只要在相应的平台安装好指定的Java虚拟机即可运行程序,不需要再次编译代码,这就是Java能一次编译,多平台运行的原因。

JVM主要由类加载器、运行期数据区、执行引擎组成,其中数据区分为方法区、堆、栈、程序计数寄存器。类加载器顾名思义就是将程序的字节码加载到内存执行的意思,字节码会被加载到方法区中。类加载器有Bootstrap ClassLoader,Platform ClassLoaders,Application ClassLoader,从上往下逐层加载需要的类。低层次的类加载器不能覆盖高层次的类加载器已经加载过的类。低层次的类加载器加载一个类的时候,需要上次层的加载器逐层确认并且同意才能加载,这被称为类加载器的双亲委托模型。如果有特殊需求,也可以自定义类加载器。

在数据区中方法区和堆是整个JVM中所有线程共享的,而栈、程序计数寄存器则是每个线程各自独立分配的,即线程创建的时候分配,线程停止的时候释放。堆存放程序运行中创建的所有类实例和数组。Java中所有对象的存储空间都是在堆中分配的,但是对象的引用是在栈中分配。也就是说在建立一个对象时从两个地方分配内存,在堆中分配的内存实际存储这个对象,而在栈中分配的内存存储的是指向堆中这个对象的引用变量。所有在方法内定义的基本类型变量,都会被每个运行这个方法的线程放入自己的栈中,线程彼此隔离,所以这些变量一定是线程安全的。方法区主要存放从磁盘加载进来的类字节码,而在程序运行过程中创建的类实例存放在堆中。程序运行的时候,实际上是以线程为单位运行的,当JVM进入启动类的main方法的时候,就会为应用程序创建一个主线程,main方法里的代码就会被这个主线程执行,每个线程有自己的Java栈,栈里存放着方法运行期间的局部变量。而当前线程执行到哪一行字节码指令,这个信息则被存放在程序计数寄存器中。

Java内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行。一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这个新值对其它线性是立即可见的,且禁止指令重排序。

JVM的垃圾回收就是将JVM堆中已经不再被使用的对象清理掉。JVM通过一种可达性分析算法进行垃圾对象的识别,具体过程是:从线程栈帧中的局部变量,或者是方法区的静态变量出发,将这些变量引用的对象进行标记,然后看这些被标记的对象是否引用了其他对象,继续进行标记,所有被标记过的对象都是被使用的对象,而那些没有被标记的对象就是可回收的垃圾对象了。进行完标记以后,JVM就会对垃圾对象占用的内存进行回收,回收主要有三种方法:清理、压缩、复制。清理即是将垃圾空间标记为空间,记录在一个空闲内存列表中,当应用程序需要创建对象的时候,就从空间列表中找一块内存分配给这个新对象。压缩是从堆的头部开始,将存活的对象拷贝到一段连续的内存空间中,那么其余的空间就是连续的空闲空间。复制是将堆空间分成两个部分,只在其中一部分创建对象,当这个部分的空间用完的时候,将标记过的可用对象复制到另一个空间中。JVM使用分代垃圾回收。将堆空间分为老年代、新生代,其中新生代又分为eden区、from(Survivor1)区、to(Survivor2)区,创建对象的时候从eden区寻找内存,当eden区内存不足时启动垃圾回收,将标记过的对象拷贝到from区,继续在eden区创建对象。当eden区再次满了的时候,将eden区和from区进行垃圾标记,将标记过的对象拷贝到to区。当eden区再次满的时候,将eden区和to区做垃圾标记,将标记的对象拷贝到from区,以此类推。当一个对象经过多次标记之后仍然存在的时候可以将该对象拷贝到老年代中。当所有内存都不足的时候,启动FullGC,对所有内存进行标记回收。默认的,新生代( Young )与老年代( Old )的比例的值为1:2 (该值可以通过参数 –XX:NewRatio来指定),即:新生代( Young ) = 1/3的堆空间大小。老年代( Old ) = 2/3的堆空间大小。其中新生代中,默认的,Eden : from : to = 8 : 1 : 1 (可以通过参数 –XX:SurvivorRatio来设定),即:Eden = 8/10的新生代空间大小,from = to = 1/10的新生代空间大小。JVM每次只会使用Eden和其中的一块Survivor区域来为对象服务,所以无论什么时候,总是有一块Survivor区域是空闲着的。因此,新生代实际可用的内存空间为9/10 (即90% )的新生代空间。JVM垃圾回收算法有:串行回收器、并行回收器、并发回收器CMS、G1回收器,Java8之后默认使用G1回收器,如果想使用CMS回收器,可以使用参数-XX:UseConcMarkSweepGC。

JVM提供的诊断工具有:JPS, JSTAT, JMAP, JSTACK, JCONSOLE, JVISUALVM等。



Java代码优化:

1. 合理并谨慎使用多线程

最佳启动线程数= [任务执行时间/(任务执行时间-IO等待时间)]*CPU内核数

最佳启动线程数和CPU内核数成正比,和IO阻塞时间成反比。如果任务都是CPU性任务,那么线程数量最多不超过CPU内核数,因为启动再多线程,CPU也来不及调度;如果任务是磁盘操作类型、网络响应类型,那么多启动线程有助于提高任务并发,提高系统吞吐能力,改善系统性能。

2. 竞态条件与临界区

在同一程序中运行多个线程本身不会导致问题,但多个线程访问相同资源的时候会产生竞态条件。在临界区中使用适当的同步就可以避免竟态条件。

3. Java线程安全

允许被多个线程安全执行的代码称为线程安全的代码。局部变量存储在线程自己的栈中,所以是线程安全的;局部的对象引用,如果在某个方法中创建的对象不会逃逸出改方法,那么它就是线程安全的;对象成员,对象成员存储在堆上,如果两个线程同时更新同一个对象的同一个成员,那这个代码就不是线程安全的。

ThreadLocal变量既是线程共享的,又是线程独享的。Java程序应避免内存泄漏。



用户头像

杉松壁

关注

还未添加个人签名 2018.03.30 加入

还未添加个人简介

评论

发布
暂无评论
架构师课程第九周 作业