Foreword
In the new generation will be divided JVM heap memory model, two years old and areas, the main area of difference between the two is that the new generation of storage shorter survival time of the object, the old store's survival time longer objects, in addition to different survival time in addition, there are different garbage collection strategies, the following collection algorithm in the JVM:
- Clear labeling
- Tags to organize
- Replication algorithm
- Generational collection algorithm
With garbage collection algorithm, if it is determined that the object is JVM garbage objects is it? Determining whether an object has survived JVM will have their own sets of algorithms to determine:
- Reference count
- Reachability analysis
With the presence of these two concepts garbage collection and determination target, analyze them again gradually.
JVM is how to determine whether the object alive?
If it allows developers to determine whether an object is useful is very simple, simply put, is: 对象没有任何引用
it considers the object can be recovered. Consider the following program code:
public class App {
public static void main(){
checkFile("/");
}
public static boolean checkFile(String path ){
File file = new File(path);
return file.exists();
}
}
Program to implement the call checkFile
when the JVM Figure probably like this:
To checkFile
after the completion of the implementation of the method, it is inside the local variables file
will be cleared along with the stack frame, this time also survive in the JVM heap the File object is useless:
If people judge very clearly found File object has been useless, that it replaced JVM is how to determine whether an object is able to survive it?
Reference count
Reference counting algorithm principle is relatively simple, there is Imagine objects that have a count
property, each time a reference to the object will cause the count
plus 1, assuming JVM when determining whether the object is alive to check the count
property and found that this property is not 0 Description there are references to other objects in the object.
Until checkFile
after completion of execution method will count becomes 0 1 Save:
As a JVM it is easy to determine whether an object survived.
However, the reference count has an obvious drawback is that the problem can not be solved, such as circular references: A -> B -> A relationship such that an object is no way to determine whether an object should not recovered.
GC Root (reachability analysis)
为什么会被称为可达性分析
算法呢?可以这样理解如果通过GC Root
能到达一个对象那么这个对象就是存活的。那什么样的对象才是GC Root
呢?
在Java语言中,可作为GC Roots的对象包括下面几种:
- 虚拟机栈中引用的对象(栈帧中的本地变量表);
- 方法区中类静态属性引用的对象;
- 方法区中常量引用的对象;
- 本地方法栈中JNI(Native方法)引用的对象。
还是用上面的例子,在checkFile
方法执行时,因为栈帧变量file
可做为GC Root
所以在执行期间JVM是绝对不会回收掉这个File对象:
但是等到checkFile
执行完成之后,这个栈帧会被弹出,其中的变量也会被释放,相应的没有GC Root
能到达堆中的File对象,这个时候就可以判断这个对象是一个无用的对象了,然后安全回收。
垃圾收回算法
标记清除
这种算法分两分:标记、清除两个阶段,
标记阶段是从根集合(GC Root)开始扫描,每到达一个对象就会标记该对象为存活状态,清除阶段在扫描完成之后将没有标记的对象给清除掉。
用一张图说明:
这个算法有个缺陷就是会产生内存碎片,如上图B被清除掉后会留下一块内存区域,如果后面需要分配大的对象就会导致没有连续的内存可供使用。
标记整理
标记整理就没有内存碎片
的问题了,也是从根集合(GC Root)开始扫描进行标记然后清除无用的对象,清除完成后它会整理内存。
这样内存就是连续的了,但是产生的另外一个问题是:每次都得移动对象,因此成本很高。
复制算法
复制算法会将JVM推分成二等分,如果堆设置的是1g,那使用复制算法的时候堆就会有被划分为两块区域各512m。给对象分配内存的时候总是使用其中的一块来分配,分配满了以后,GC就会进行标记,然后将存活的对象移动到另外一块空白的区域,然后清除掉所有没有存活的对象,这样重复的处理,始终就会有一块空白的区域没有被合理的利用到。
两块区域交替使用,最大问题就是会导致空间的浪费,现在堆内存的使用率只有50%。
分代回收
新生代回收
JVM的堆分为新生代和老年代,两种类型有不同的特性,根据它们的特性来选择不同的回收算法,这种算法会将新生代划分为一块Eden
和二个Survivor
区:
如上面的图有三块区域它们会按照8:1:1的比例进行分配,如1000m的堆Eden
是800m,二个Survivor
各占100m,那它们是如何运行的呢?
- 始终会有一块
Survivor
是空着的,内存使用率是90% - 程序运行会在
Eden
和其中一块Survivor 1
中分配内存 - 等到执行
Minor gc
,会将存活下来的对象移动到空着的Survivor 2
中 - 然后在
Eden
和Survivor 2
中继续分配内存,Survivor 1
空着等着下次使用
这样就能使内存使用率达到90%,也不会产生内存碎片。
老年代回收
老年代对象即使进行了垃圾回收,对象的存活率也高,所以采用标记清除或标记整理算法都是不错的选择,这里就不做阐述。