上期我们讲到LoadRunner性能测堆与栈,这期我们讲LoadRunner性能测试GC回收机制。
GC回收机制
所谓的GC回收就是回收一些不用的内存,因为程序在运行过程中,这些对象运行结束后都得释放出来,这些对象释放后,就必须对这些在内进行回收。如果不能有效的加收这些内存就可以导致内存溢出的问题。
那么JVMGC是怎么判断对象可以被回收了呢?通常可以通过以下情况来判断对象是否可以被回收。 1)对象没有被引用。 2)作用域发生未捕获到的异常信息。 3)程序在作用域正常执行完毕。 4)程序执行了system.exit的方法。 5)程序出现异常意外终止。 关于如何判断垃圾的算法通常会有两种:引用计数法和可达性分析算法。
1)引用计数法 引用计数法是为每个对象添加一个计数器,相当于一个变量用来计算对象引用和回收的情况,当该对象被引用时计数器就会加1,如图10-23所示,当引用失效时计数器减1。最后判断对象计数器是否为0,如果对象计数器为0,那么表示这个对象可以回被回收。但引用计数法有一个缺点,这个无法循环使用。
先创建一个字符串,String str = new String("shenzhen");,这时候 " shenzhen " 有一个引用,就是str。然后将str设置为null,这时候 " shenzhen " 的引用次数就等于 0 了,在引用计数算法中,意味着这块内容就需要被回收了。
2)可达性分析算法 关于如何判断垃圾的算法通常会有两种:引用计数法和可达性分析算法。 在Java中,是通过可达性分析(ReachabilityAnalysis)来判定对象是否存活的。该算法的思路是通过以GCROOT对象作为搜索起始点向下搜索,搜索经过的路径称之为引用链(ReferenceChain)当一个对象到GCRoots没有任何引用链相连时(即从GCRoots节点到该节点不可达),则证明该对象是不可用的。则这个对象是可以回收的,如图所示。
如上图所示,Object1到object5这五个对象是可以到达GCRoot的,说明不需要回收,但是Object6、Object7和Object8对GCRoot节点不可达,说明这三个对象是可以被回收。
但即使对象不可以到达GCRoot也不一定就立即确定对象一定能回收,对象最终是否被回收,必须由finalize()方法来确定,finalize()方法Object类中定义的,每个类可以重写这个方法,但一般不建议对这个方法进行重写,因为这个方法在调用时存在太多的不确定性。
要确定对象是否真的被回收,需要finalize()方法进行两次标记,第一次标记并进行一次筛选,筛选对象是否有必要执行finalize()方法,当对象没有覆盖finalize方法,或者finzlize方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”,对象被回收。
如果该对象被判定为必须执行finalize()方法,那么这个对象就会被放置在一个名为F-Queue的队列之中,并会在由虚拟机自动建立的、低优先级的Finalizer线程中执行,即在虚拟机中触发这个方法,然后GC会对F-Queue队列中的对象进行第二次标记,如果对象被第二次标记,那么这个对象就会被回收了。如果在finalize()中没有被第二次标记,那么就只要重新与引用链上的任何一个对象建立关联即可。