首页 > 编程知识 正文

java面向对象,卡在发送kernelcache

时间:2023-05-06 10:27:58 阅读:130568 作者:899

这个问题是我在磨牛客面经的时候遇到的,特意整理成个人的常规面题文件,所以这个问题主要考察了finalize方法的影响。 java

java提供了finalize方法来帮助释放资源,就像c中的析构函数一样。 但是,现在被广泛认识的是不使用。 为什么会这样呢? 因为这会影响java虚拟机的垃圾回收。 这篇文章就此进行说明。 面试

1、为什么会有影响

我们知道java虚拟机会将其识别为垃圾对象,进行垃圾回收的对象GCRoot无法到达,但是如果此对象包含finalize函数,则性质会不同。 怎么不一样? ide

java虚拟机进行垃圾回收时,如果看到此对象类包含finalize函数,则将此函数传递给FinalizerThread,而包含此finalize的对象是FinalizerThread 函数

除非finalize运行,否则这些对象一直存在于堆中,但这里只有四个对象包含finalize,影响并不大。 如果有一万或十万人呢? 这有很大的影响。 工具

finalize原理其实很简单。 现在让我们简单地整理一下。 spa

)1)对象在初始化过程中判断是否改写了finalize,判断两个字段标志has_finalizer_flag和RegisterFinalizersAtInit。 插件

)2)改写finalize时,将当前对象注册到FinalizerThread的参考队列中。 注册后的对象称为Finalizer。 方法是调用register_finalizer函数。 此时,java虚拟机当前对该对象有引用,因此不进行垃圾回收。 线程

)3)对象开始调用,FinalizerThread线程从ReferenceQueue队列中检索Finalizer对象。 开始执行finalize方法。 在运行之前,此对象位于堆中。 代码

)4)对象执行完成后,将此Finalizer对象从队列中删除,java虚拟机认为对象未被引用,然后进行垃圾回收。 对象

这就是整个过程。 但是,现在我们主要看看finalize方法对垃圾回收的影响。 实际上,第3步,即此对象包含finalize,它会在排队但未调用时继续占用内存。

注意:这里其实是面条问题。 看着牛客网上的面经,有人被问到过。 也就是说,GCRoot收不到的对象,会马上被垃圾回收吗?

用案例分析一下波浪吧:

2、案例演示

组成一个班吧

` publicclassTestFinalizer {

publicstaticclassFdd {

分配//1m

私有字节[ ] content=new byte [ 1024 * 1024 ];

@Override

protectedvoidfinalize (

system.out.println(finalize运行);

}

}

publicstaticvoidmain (字符串[ ] args ) {

for(inti=0; I

Fddfdd=newFdd (;

}

}

}

`

现在做了班,设定参数吧。

` #最大堆内存

-Xmx5m

最小堆内存

-Xms5m

堆内存溢出错误打印

- xx : heapdumponoutofmemoryerror

将有关堆的信息保存到以下路径

- xx : heap dump path=f :/a.dump `

在main方法中,我们创建了1000个软驱对象。 如果不执行finalize方法,将进行垃圾回收,因为没有调用。 此时,制作几个都没有问题。 但是,如果finalize方法存在,则不是。

` Java.lang.out of memory error : javaheapspace

Dumping heap to F:/a.dump .

已完成

已完成

已完成

已完成

已完成

已完成

已完成

unabletocreatef :/a.dump :文件导出

exceptioninthread ' main ' Java.lang.out of memory error 3360 javaheapspace

atcom.FDD.chapter2. test finalizer $ FDD.(test finalizer.Java :6 )。

atcom.FDD.chapter2. test finalizer.main (test finalizer.Java :14 ) `

我们看到所有对象都运行finalize,在运行之前一直呆在堆里,运行结束后就被清理了,所以我们在这里运行了五次以上的finalize方法。 但是,如果对象超过了我们设置的5M,就会发生内存溢出。 一句话概括起来,出现了对象的堆积。 现在使用MAT工具分析一下吧。

Mat工具是插件,也可以下载自身。 下载结束后,打开我们刚生成的a.dump就可以了。

下图是分析的结果:

a内容属于Finalizer,也就是我们的软驱,b包含了比较多、剩下的乱七八糟的信息。 虽然也可以看到剩下的信息。 在MAT工具上。 有些准备与正在运行的finalizer运行。

确定,剩下的信息不会再显示了。

结论

GCRoot无法到达的对象不会立即回收到垃圾中,而是首先确定是否包含finalize方法,如果存在,则先运行finalize方法。 如果有很多这样的对象,GCRoot将无法立即到达,不再有用,留在内存中,并影响程序的效率。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。