1.介绍下Java内存区域(运行时数据区)
java内存区域分为:虚拟机栈(执行java代码时所使用的栈,存放基本类型变量,对象引用,方法的形参,运行时上下文环境,操作指令区,线程私有)
,本地方法栈(用于执行native方法时所使用的栈,在HotStop中与虚拟机栈合并为一个栈),
堆(用于存放几乎new出来的所有的对象实例,是线程共享的),
方法区(包含类信息,静态变量,常量,运行时常量池等,线程共享)
程序计数器(是程序当前执行的字节码行号指示器,线程私有,通过改变程序计数器的值)
2.HotSpot为什么要分为新生代和老年代?
为了更好的分配内存和回收内存,在java程序的运行过程中,对象的产生于销毁是非常普遍的事情,新生代主要是存放一些使用周期较短暂的对象,比如局部变量所引用的对象,在执行完方法后该引用会直接被释放,此时的对象实例还在堆中,但已经是一个可被回收的"垃圾"了,因为没有任何引用指向该对象,而老年代负责存放周期较长即创建到销毁的过程中将被多次使用的对象.
3.对象头中存放哪些东西?
Hotspot虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的自身运行时数据(哈希码、GC分代年龄、锁状态标志等等),另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是那个类的实例。
4.对象的访问定位方式有几种?
①使用句柄和②直接指针
5.如何判断对象是否死亡(两种方法)
①引用计数法
新创建对象时,创建一个引用计数器,当前对象的印象增加时,计数器+1,同理-1,当计数器的值为0时,说明已经没有引用指向该对象,说明该对象已死
②可达性分析法
通过GC Root为根,寻找与GC Root有引用链的对象即为可达,说明对象依然存活,否则说明该对象已死亡(HotSpot使用这种方法,但也不是一定死亡,至少会经过两次标记才会确定真正死亡,可达性分析中无法与GC Root存在引用链的对象进行第一次标记,查看其是否有必要执行finalize()方法,若对象没有重写或者已经被执行过finalize()方法,则没有必要,直接回收,避免回收的方式是对象的类重写finalize()方法,并在方法中将this重新连接到某引用上,这样就会退出等待回收队列,注:一个对象的finalize()方法只能被执行一次)
6.简单的介绍一下强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)。
强引用:比如 Student stu = new Student();这就是强引用
软引用:若存在软引用即在进行垃圾回收后,若内存足够使用,则保留该对象,若还是不够使用,则可以将软引用的对象进行回收
弱引用:若一个对象只存在弱引用时,该对象可存活至下一次垃圾回收之前,在下一次垃圾回收时被回收
虚引用:没有实质性的作用,也不会对垃圾回收产生影响,主要是用于在垃圾时候时做日志使用
区别:虚引用必须与引用队列联合使用
7.垃圾收集有哪些算法,各自的特点?
垃圾回收算法包括三种:
①标记-清除算法
对堆中可回收的对象进行标记并清除,有两大不足,一是效率低下,标记与清除的效率都比较低,二是会造成大量的碎片,导致内存容量大但是不存在较大的连续内存区域,一般不使用
②标记-整理算法
对堆中可回收的对象进行标记,并处理之后,将依然存活的对象进行整理,即紧凑,将所有不可使用的区域/可使用的区域放置在连续的一段内存中,供程序使用,一般用于老年代
③复制算法
一般用于新生代,将新生代整体划分为Eden区与两个Survivor,每次使用Eden区和一个Survivor区来存储对象,因为新生代对象存在周期短,所以会产生大量需要回收的对象,复制算法就是将存活的对象复制放置在另一个Survivor区中,并将Eden区与一个Survivor区进行清理,特点是效率极高,缺点是浪费部分内存不能使用(但在HotStop中已经做出改良,Eden区与Survivor区的比例默认是8:1)即新生代有10%的区域不能作为对象存储所用
8.常见的垃圾回收器有那些?
单线程(Serial)收集器(新生代,复制算法),
多线程(ParNew)收集器(新生代,复制算法),
Parallel Scavenge收集器(注重吞吐量,新生代,复制算法)
对应的老年代回收器:
Serial Old(老年代,单线程标记-整理算法)
CMS(老年代,可实现真正并行的收集器,采用标记-清除算法,注重用户体验),
G1(可由用户控制回收时间与吞吐量,注重用户体验)
9.介绍一下CMS,G1收集器。
CMS(Concurrent Mark Sweep)并发标记清除收集器,从名字上可以看出采用的回收算法是标记清除 ,也导致它的一大缺点是造成大量内存碎片.CMS的目的是获取最短回收停顿时间,非常注重用户体验
收集过程:
①初始标记
对GC Root直接存在引用链的对象进行标记(速度很快,所以采用了Stop The World的单线程处理)
②并发标记
开启用户线程与标记线程并发 去标记与GC Root存在引用链的可达对象,这个过程中用户线程可以继续运行,该线程会标记自开启该线程之前的可达对象,但对于标记期间,用户线程变动的对象无法进行标记
③重新标记
对并发标记过程中用户变动的对象进行标记,采用单线程,因为也很快
④并发清除
开启用户线程,对标记的区域进行清扫,释放回收掉未标记对象的内存
总结三个缺点:
①对系统资源过于敏感(当前CPU+3/4作为垃圾回收线程,在CPU较小的情况下垃圾回收线程所占比过大,影响用户体验)
②无法清除浮动垃圾(即在并发清除的过程中用户线程又产生的垃圾对象)
③产生大量碎片
G1(Garbage-First)收集器,根据用户所设置的回收时间,从而回收价值最大部分的内存
也采用分区处理,使用算法从全局角度来看是标记-整理算法,局部来看是复制算法
10.Minor Gc和Full GC 有什么不同呢?
Minor GC即新生代垃圾回收,采用复制回收算法,效率高,适用于新生代这种死亡率较高的区域,并且有老年代作为担保,一旦新生代存活的对象需要内存大于一个Survivor区时,会将多出来的对象转移至老年代
Full GC即老年代垃圾回收,采用标记-整理回收算法,老年代的对象一般死亡率较低,而且没有担保,所以无法采用复制回收算法.