根据《深入理解java虚拟机》这本书总结
书中有一段话,大体的意思是:java和c之间有一堵墙,墙里的人想出来,墙外的人想进去,这堵墙就是垃圾回收机制了。
一、为什么要理解垃圾回收机制?
java的垃圾回收,是自动完成的,一般情况下并不需要去关注,但是当遇到一些并发量、数据量比较大的时候,可能就会出现一些关于内存益处的问题。这时候,解决的办法,就得依靠对垃圾回收机制来理解和进行调优了。我们可以分析,是哪部分内存出现了问题,分析哪些多余的对象应为代码问题没有被回收。我想这就是学java的人想进去这堵墙的原因吧。
二、垃圾回收的主要作用对象?
jvm内存,主要分五个部分:堆、方法区、栈、本地方法栈、程序计数器。这五个区域中,除了程序计数器,别的四个区域都是可能会存在内存溢出问题的。但是,对于本地方法栈和栈来说,jvm会在方法入栈时候开辟内存,出栈则回收内存,没有什么很复杂的算法和操作。所以,垃圾回收机制,主要正对的是堆和方法区这两部分内存区域中对象的回收。
三、如何寻找垃圾(无用对象)?
在堆和方法区回收垃圾对象,需要先找到无用对象,一般有两种方法:
1、引用计数法
为每个对象添加一个记录被引用次数的属性,当对象引用或者引用失效时,进行更新+1或者-1的操作,并且随时更新,当gc发生的时候,如果引用计数为0,则判断对象可以进行回收。
但是这种方法有个弊端,如果两个对象存在着相互引用的情况,两个对象本质上都无地方使用了,但是因为两个无用对象相互引用,那么计数器永远不肯呢个为0,就永远不能清楚这两个对象了。所以一般jvm虚拟机,不会直接使用这种方法。
2、可达性算法
(1)虚拟机会设置一些root节点,一般可以作为root节点的有:栈帧中本地变量表引用对象、本地方法引用对象、方法区中常量引用对象、方法区中静态变量引用的对象。
(2)根据这些root节点,向下搜索,所有走过的路径所涉及的对象,即是有用对象,其余的都为无用对象。这样,即使一些相互引用的对象,但是与root节点无关联,也会被标记回收。
四、垃圾的自救
jvm给了即将被回收的垃圾一个自救的机会,所以在对对象进行垃圾gc标记的时候,会有两个过程:
1、第一次标记,会查看该对象是否重新了finalize()方法,如果重写了该方法,那就标记需要执行这个方法,如果没有重新,则标记为垃圾,在下次gc进行回收。
2、如果需要执行finalize方法,会在回收之前执行,如果在该方法中进行本对象重新引用,则成功自救,将不进行垃圾回收。如果没有重新引用,则仍然会在下次gc的时候进行回收。
*一个对象的finalize方法,有且只能执行一次,所以顶多能自救一次