对于基于线程存在的PCR以及栈区域,具备确定性。而堆以及方法区则不一样(重点讨论)。
对象已死?
1、引用计数算法(不使用):难以解决对象之间相互循环引用的问题。
2、可达性分析算法:设置GCRoots,搜索引用链,大概图论的可达概念。
都是根据引用?
1、强引用:new出来的,怎样都不会被回收。
2、软引用:溢出之前进行回收,如果回收完还是溢出就报错。
3、弱引用:下次垃圾收集肯定被收。
4、虚引用:。。。
若被判断不可达,还需要经过两次标记才确定回收。
垃圾收集算法:
1、标记-清除算法:效率不高,容易产生内存碎片。
2、复制算法:将内存分成一半,满的时候将存活的复制到另外一块,原来的那一半全清理掉。实际上是采用9:1的划分。
3、标记-整理算法:标记完存活的对象向一端移动,清理端边界以外的内存。
4、分代收集算法:使用的算法,不同存活周期(代)在不同块内,各部分根据实际情况使用上面的某一种方法。
在Eden出生并且经过第一次Minor GC后仍然存活,并移动到Survivor,那么年龄设置为1,之后不断经过Minor GC,年龄就加1,到15岁就是老年代。
堆大小 = 新生代 + 老年代
默认的,新生代与老年代的比例的值为 1:2,即:新生代 = 1/3 的堆空间大小。老年代 = 2/3 的堆空间大小。
新生代又被划分为三个区域:Eden、From Survivor、To Survivor。
默认的,Eden:From:To = 8:1:1
JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块Survivor区域是空闲着的。
因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。
Java 中的堆也是 GC 收集垃圾的主要区域。GC 分为两种:Minor GC、FullGC ( 或称为 Major GC )。
Minor GC 是发生在新生代中的垃圾收集动作,所采用的是复制算法。
Full GC 是发生在老年代的垃圾收集动作,所采用的是标记-清除算法。