有如下代码:
public class TestOOM{
public static void main(String args[]){
while(true){
Object object = new Object();
}
}
}
这种情况下,jvm的垃圾回收机制会对其中的object进行垃圾回收吗?
如果不会,那我们平时写的代码for循环、while循环不在少数,而且也没有对其中的引用写类似于 object = null的断开实例的代码,那岂不是一个系统运行的越久,堆内存占用的就越大?
如果会,那是什么原理,按照可达性算法(GCRoots)的概念,只有当对象在GCRoots的引用链中不可达时,才会判定为垃圾对象,像是上述代码中的object引用,仍然可达,照理说不会被回收啊?
首先第一点这个不会回收;因为局部变量也属于GC roots。死循环这个栈帧会一直存在了,所以不会回收。
第二点,一般的方法,for或者while 只要你当前的局部变量没要逃逸,当栈帧结束都会自动回收,也就是局部变量和对象的连接会断开,所以不需要设置null
第三,如果当前的局部变量逃逸出去,也要看是否一直长时间被使用,长时间使用就会出现内存溢出的问题,这时候就需要设置为null,等待GC的回收。
有啥不懂可以问我
1 垃圾回收区域
GC主要关注于堆中(重点关注堆)和方法区的垃圾收集
引申点:虚拟机栈,本地方法栈,程序计数器不用考虑GC;不会发生OOM的区域只有程序计数器。
Java 内存运行时区域中的程序计数器、虚拟机栈、本地方法栈随线程而生灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的(尽管在运行期会由 JIT 编译器进行一些优化),因此这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。
而 Java 堆不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间时才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器所关注的是这部分内存。
从次数上讲:
1 频繁收集Young区
&emsp2; 较少收集Old区
3 基本不收集Perm区(元空间)
2 垃圾回收相关算法
在堆里存放着几乎所有的Java对象实例,在GC执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有被标记为己经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。
那么在JVM中究竟是如何标记一个死亡对象呢?简单来说,当一个对象已经不再被任何的存活对象继续引用时,就可以宣判为已经死亡。