这道题是我在看牛客的面经时遇到的,特地整理在我的正经面试题文档中,所以这道题主要考察finalize方法的影响。Java提供了finalize方法可以帮助我们释放资源,类似于C++中的析构函数。这篇文章对此进行了解释。1、为什么会受影响我们都知道一个对象GCRoot是不可达的,java虚拟机认为它是一个垃圾对象,它会进行垃圾回收,但是如果这个对象包含finalize函数,性质就不一样了。为什么不同?java虚拟机在进行垃圾回收时,一看到这个对象类包含finalize函数,就会把这个函数交给FinalizerThread处理,包含这个finalize的对象就会加入到FinalizerThread的执行队列中,并使用链表将这些最终确定的对象串在一起。他的影响是只要不执行finalize,这些对象就会一直存在于堆区,但是这里只有4个包含finalize的对象,影响没有那么大。如果有10,000或100,000怎么办?这个影响大。finalize的原理其实很简单,这里简单总结一下:(1)在初始化过程中,对象会通过判断has_finalizer_flag和RegisterFinalizersAtInit这两个字段标志来判断是否重写finalize。(2)如果finalize被重写,将当前对象注册到FinalizerThread的ReferenceQueue队列中。注册后的对象称为Finalizer。方法是调用register_finalizer函数。这时java虚拟机看到当前有这个对象的引用,所以不进行垃圾回收。(3)对象开始被调用,FinalizerThread线程负责从ReferenceQueue队列中获取Finalizer对象。开始执行finalize方法。在执行之前,这个对象一直在堆中。(4)对象执行完毕后,将Finalizer对象从队列中移除,java虚拟机看到该对象不再被引用,进行垃圾回收。这就是整个过程。但是这里主要看一下finalize方法对垃圾回收的影响。其实就是在第三步,也就是对象包含finalize,进入队列但是还没有被调用,会一直占用内存。注意:这实际上是一道面试题。看牛客网采访的时候,看到有人问。也就是说,GCRoot无法访问的对象会立即被垃圾回收吗?我们用一个案例来分析一波:2.案例演示我们创建一个类publicclassTestFinalizer{publicstaticclassFdd{//allocate1Mprivatebyte[]content=newbyte[1024*1024];@Overrideprotectedvoidfinalize(){System.out.println("finalizeisexecuted");}}publicstaticvoidmain(String[]args){for(inti=0;i<1000;i++){Fddfdd=newFdd();}}}现在已经创建了类,让我们设置参数。#最大堆内存-Xmx5m#最小堆内存-Xms5m#打印堆内存溢出错误-XX:+HeapDumpOnOutOfMemoryError#保存堆相关信息在以下路径-XX:HeapDumpPath=F:/a.dump是在main方法中创建的1000个Fdd对象,如果没有执行finalize方法,会因为没有调用而进行垃圾回收。这个时候,不管我们创建多少,都不会有问题。但是如果有finalize方法就不一样了。java.lang.OutOfMemoryError:JavaheapspaceDumpingheaptoF:/a.dump...finalize被执行finalize被执行finalize被执行finalize被执行.OutOfMemoryError:Javaheapspaceatcom.fdd.chapter2.TestFinalizer$Fdd.
