Gc对象的性质
可触及
我们都知道,gc对无用对象进行标记,然后回收。
我们需要了解一下,gc是如何识别到这个对象是无用对象的?
从根节点有链条链到这个对象,我们就说这个对象是可触及的,可触及的对象就不应该被回收。
可复活
虽然现阶段不可触及,但是后面有可能再次被标记为可触及。
不可触及
不可触及对象就可回收了,不可触及的对象再也不可能被标记成可触及了。
使用finalize方法来复活对象
使用finalize的问题:
1. 如果使用finalize复活之后,忘记进行置null,那么虚拟机是否会回收这个被复活的对象呢?
2. 因为finalize是gc的时候发生的,gc的发生是虚拟机调用的,调用的时候存在不确定性,finalize何时被调用是不知道的。
根的引用链。
栈中正在运行的方法里面的对象。
全局变量。
Java调用本地方法栈所引用的对象。
Stop-The-World
简单理解就是整个jvm被挂起,只能做gc。
原因:
类似于上一篇提到的,进行标记的时候,如果一个对象在标记后才new进去的话,这个对象会被马上清除,因为标记的时候这个对象是不存在,也就是说从gc root到这个对象是没有引用链的。
Gc root必须保证在一个内存一致性的情况下进行gc,所以会存在全局停顿。
危害:
长时间服务停止,没有响应(将用户正常工作的线程全部暂停掉)
遇到HA系统,可能引起主备切换,严重危害生产环境。
备注:HA:High Available,高可用性集群。
比如上面的这主机和备机:现在是主机在工作,此时如果主机正在GC造成长时间停顿,那么备机就会监测到主机没有工作,于是备机开始工作了;但是主机不工作只是暂时的,当GC结束之后,主机又开始工作了,那么这样的话,主机和备机就同时工作了。主机和备机同时工作其实是非常危险的,很有可能会导致应用程序不一致、不能提供正常的服务等,进而影响生产环境。
样例构造:
printThread线程,每0.1秒打印。
MyThread线程,1毫秒占用了0.5m。
100毫秒,占用了50m。
大概执行10次100毫秒后,堆就满了。
可以看到,3153之后应该马上接着3253,但是并没有,因为3153后对空间满了。Gc暂停了所有程序,这个时候打印线程也被中止了。然后gc进行内存回收,大约用了3504-3153毫秒。
总共经历了2次gc