JVM
笔者能力有限,总结有误的地方,请读者协作更正。
1.类的加载机制
关注点: 什么是类的加载 类的生命周期 类加载器 双亲委派模型
1)谈一谈类的实例化顺序,比如:父类静态数据,构造函数,字段等的执行顺序? 先静态-->先父后子-->非静态代码块-->构造函数
2)java代码的执行编译过程 ? 主要就是两部:java源文件由编译器编译成字节码文件,字节码文件由虚拟机解释执行。
具体来说,源码需要经过词法分析器组件,语法分析器组件,语义分析器组件,最后经过代码生成器组件编译成字节码文件。
3)java类的生命周期?
一个java类的完整的生命周期会经历加载、连接、初始化、使用、和卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直接被使用的情况。
4)类加载器?
类加载器是java语言强大的特征之一, 默认情况下有三种类加载器(引导类加载器,扩展类加载器,应用类加载器),我们也可以自定义类加载器。 应用程序的每一个类都由ClassLoader加载,java类是被动态的加载到内存,java的一大特点,也称为运行时绑定。
5)什么是类加载器的双亲委派模型?
就是类加载器之间的的层次关系,该模型要求除了顶层的启动类加载器之外,其余的类加载器都要有父类加载器,而且这种关系一般通过组合关系来实现,而不是通过继承。
某一个类加载器在接到加载类的请求时候,首先会将任务委托给父类加载,依次递归,如果父类加载器可以完成类加载任务,则成功返回;如果父类加载器无法完成加载任务,将抛出ClassNotFoundException异常后,再调用自己的findClass()方法进行加载,依次类推。
好处:
防止内存中出现多份同样的字节码。 如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,多个类加载器都去加载这个类到内存中,系统中将会出现多个不同的Object类,那么类之间的比较结果及类的唯一性将无法保证,将会给虚拟机的安全带来隐患。
2.JVM内存结构
关注点: 内存结构 对象分配规则
1)JVM的内存分配?
Java虚拟机的运行时数据区包括:Java堆、Java虚拟机栈、方法区、PC寄存器、本地方法栈,还有常量池。它们被分为两大类-------线程共享、私有数据区。
2)虚拟机内存分配的各个区域作用?
堆:
new处理的对象都存放在堆中,堆的大小可以通过-Xmx和-Xms来控制; 堆被分为新生代、旧生代、持久代新创建的对象都用新生代内存分配,旧生代用于存放新生代中多次经过垃圾回收仍然存活的对象;
栈:
每个线程执行每个方法时候都会在栈中申请一个栈帧,用于存放此次方法调用过程中临时的变量、参数、中间结果等;
本地方法栈:
用于支持native方法执行,存储每个native方法调用的状态
方法区:
持久代实现方法区,主要用来存放已经加载的类的信息,方法,常量等;可以通过XX:PermSize和-XX:MaxPermSize来指定持久带初始化值和最大值。
3.GC算法 垃圾回收
关注点: 对象存活判断 GC算法 垃圾回收器
1)垃圾回收采用什么算法实现?按照基本策略分为:
引用计数器(Reference Counting): 比较旧的一个算法,原理是此对象有一个引用;增加一个计数,增加一个引用;删除一个引用,减少一个计数。 垃圾回收时,只收集计数为0的对象。 存在最致命的问题是,无法处理循环引用的问题。
标记-清除(Mark-Sweep): 此算法分为两个阶段,第一个阶段从引用根节点开始标记被引用的对象; 第二个阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。
复制(Copying): 此算法把内存空间划分为相等的区域,每次只使用其中一个区域,垃圾回收时候,遍历当前的区域,把正在使用中的对象复制到另一个区域。 算法每次只处理正在使用的对象,因为复制成本小,同时复制过去之后还能进行相应的内存调整,不会出现碎片问题。 缺点就是,需要两倍的内存空间。
标记-整理(Mark-Compact): 此算法集合了“标记-清除”和“复制”两个算法的优点分为两个阶段,第一阶段从根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把清除未标记的对象并且存活的对象“压缩”到堆的其中一块,按照顺序排放。 此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。
2)Java对新生代和旧生代采取了不同的垃圾回收机制
新生代的GC: 新生代通常存活时间较短,居于Coping算法来进行回收; 采用空指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间位置,当有新的对象要分配内存时候,用于检查空间是否足够,不够就触发GC; 在执行机制上提供了串行GC,并行回收GC,和并行GC;
旧生代GC: 旧生代GC对象存活的时间比较长,比较稳定;
采用标记(Mark)算法来进行回收,就是扫描出存活的对象,回收位被标记的对象,回收后对对腾出的空间进行合并。 在执行机制上JVM提供了串行GC,并行GC和并发GC;
4.GC分析 命令调优
关注点: GC日志分析 调优命令 调优工具
调优主要的目的是减少GC的频率和Full GC的次数,过多的GC和Full GC是会占用很多的系统资源(主要是CPU),影响系统的吞吐量。
调优手段:主要是通过控制堆内存的各个部分的比例和GC策略来实现,JVM提供两种较为简单的GC策略的设置方式;
1)吞吐量优先 JVM以吞吐量为指标,自行选择相应的GC策略及控制新生代与旧生代的大小比例,来达到吞吐量指标。这个值可由-XX:GCTimeRatio=n来设置
2)暂停时间优先 JVM以暂停时间为指标,自行选择相应的GC策略及控制新生代与旧生代的大小比例,尽量保证每次GC造成的应用停止时间都在指定的数值范围内完成。这个值可由-XX:MaxGCPauseRatio=n来设置