由于jdk版本处在高速迭代中,java有多种版本的收集器,比如serial收集器,ParNew收集器,cms收集器,G1收集器.
串行回收与并行回收:
串行回收就是同一时间只能有一个线程操作
并行回收就是同一时间有多个线程同时操作,但即使是并行回收,也仅是最大限度减少stop-the-world的时间.
Serial收集器:
单线程,分为Serial新生代收集器和Serial老年代,Serial新生代采用复制算法,Serial老年代采用标记-整理算法.
ParNew收集器:
多线程,只工作在新生代,使用复制算法.
CMS收集器:
多线程,可以划分为4个阶段,初始阶段,并发阶段,再次标记阶段,并发清除阶段.
初始阶段:使用根搜索算法,stop-the-world,找到可达的目标对象.
并发阶段:标记不可达的为垃圾对象.
再次标记阶段:由于上一阶段与程序运行是同步的,所以不保证此时该对象关系不变,所以stop-the-world,再次标记.
并发清除:清除垃圾对象.
使用的是标记-清除算法,所以容易产生碎片化,不能使用指针碰撞,只能使用空闲列表进行内存分配.
G1收集器:
将java堆分为2048个独立块,每一块物理上不一定是连续的,在垃圾回收时,仅扫描块内存较大的,从而避免了全局扫面,减少了stop-the-world的时间.
Serial收集器效率一定比ParNew低吗:
如果是单核cpu,未必,因为线程的切换需要时间.
内存分配的方法:指针碰撞(针对连续空间,比如采用标记-整理,用一个头指针指向下一个可用空间),空闲列表(针对不连续空间,比如采用标记-清除)
新生代gc非常频繁,优先考虑速度,并且新生代空间较小,所以采用复制算法,而老年代占据空间较大,gx不频繁,采用复制算法代价太大,一般采用整理算法.
逃逸分析和栈上分配:
当一个对象定义在方法的内部,那么访问权限限制在方法内部,如果外部方法访问,就发生了逃逸。定义在类的内部可以分配内存在java栈上,避免了gc消耗,随着方法的执行而创建,随着方法的结束而销毁空间.
client方法:
初始化类中的类变量,使用用户指定值覆盖掉jvm在准备阶段为其设置的值.(比如private static int i=10;)
三种引用类型:类类型,数组类型,接口类型.
四种引用类型:强引用,弱引用,软引用,虚引用.
(上面这两个我也是醉了...)