堆—分为 永久区、老年代、新生代
永久区:即方法区,存放的是类的信息以及运行时常量池
老年代:能够逃过多次GC的对象,放在老年代。这个逃出的次数,可以
认为给定 。
新生代:又分为三个部分 eden区,from区和to区。
分区是为了,在不同的分区采用不同的GC算法。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GC前提
:如何判断对象已经无用了。
两种算法:引用计数法;可达性分析
引用计数法,如python、flashplayer的GC算法采用的是引用计数法。
引用计数法缺陷:1 不能处理 循环引用问题
2 要么在对象外部,或则对象内部,对于每个对象实
例,都需要维护一个引用计数器。开销大。
发生时间点:每次有对象的引用增加,或者消减的时候都会触发。
引用计数法:思想简单???
可达性分析,常用的方法。用来集中处理不可达的对象。
发生的时间点:在 每次GC前,计算一次。不需要对每个局部的对象都维护一个计数器。
思想:从GCRoot开始,搜索可达的对象。搜索到的是可达的,搜索不到的则不可达,将被GC回收
哪些变量可以当做GCRoot?
: java栈帧中的局部变量的对象引用、方法区的静态对象变量引用、方法区的静态常量对象引用?? 本地方法栈帧中的native方法中的对象引用。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GC的种类:
Mirror GC,FullGC
最小GC:只对新生代进行GC,因为新生代比较活跃,里面有些对象很快就创建和弃用。 发生点:当为对象分配空间的时候,空间不足够的时候,就会触发 Mirror GC。
FullGC:对所有的堆空间(包括 永久区、老年代、新生代 )
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GC算法:
复制算法,标记清除算法,标记整理算法
新生代:复制算法
因为老年代的对象不活跃,比较稳定,所以如果对老年代也用复制算法,那些稳定的对象就会总是被复制,浪费了系统时间。而新生代的对象比较活跃,所以用复制算法。
复制算法;原本是分为两个区域(A,B),优化以后,划分成3个区域(eden、from、to)其中常用比例是8:1:1
1 如果from、to的区域划分大了,那么内存的利用率下降,因为(from、to)每个时刻,总有一个不被使用。
2 (from、to)如果划分的太小,那么在把(eden、from/to(其中的一块))复制的时候,会有更多的对象逃逸到老年代。造成老年代变得不稳定。
标记清除算法:
第一次,访问所有活跃的对象,并进行标记
第二次,清除那些未标记的对象
缺点:会造成很多碎片
标记整理算法:
综合了上述两种算法的有点,但是系统开销大。
首先使用标记清除算法,然后把活跃的对象(而不是碎片)进行整理,聚合。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
其他
对象的访问定位:
2种方式
1 使用句柄来定位对象(需要二次定位) ,即使产生GC,对象移动但是reference稳定,只需要改变句柄中的 数据。
2 使用直接指针来对位对象,速度快,只需要一次指针定位。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
参考网站:http://uule.iteye.com/blog/1894724 帖子写的很好!
https://www.zhihu.com/question/21663879 知乎帖子,也很好!