关于垃圾回收有三个经典问题: 1、哪些内存需要回收? 2、什么时候回收? 3、如何回收?
垃圾收集机制是Java的招牌能力,极大地提高了开发效率。如今,垃圾收集几乎成为现代语言的标配,即使经过如此长时间的发展,Java的垃圾收集机制仍然在不断的演进中,不同大小的设备、不同特征的应用场景,对垃圾收集提出了新的挑战,这当然也是面试的热点。
什么是垃圾? 垃圾(Garbage)是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。 如果不及时对内存中的垃圾进行清理,那么,这些垃圾对象所占的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用。甚至可能导致内存溢出。
为什么需要GC? 对于高级语言来说,一个基本认知是如果不进行垃圾回收,内存退早都会被消耗完,因为不断地分 配内存空间而不进行回收,就好像不停地生产生活垃圾而从来不打扫一样。 除了释放没用的对象,垃圾回收也可以清除内存里的记录碎片。碎片整理将所占用的堆内存移到堆的一端,以便JVM将整理出的内存分配给新的对象。 随着应用程序所应付的业务越来越庞大、复杂,用户越来越多,没有GC就不能保证应用程序的正常进行。而经常造成STW的GC又跟不上实际的需求,所以才会不断地尝试对GC进行优化。 另方面: 对于Java开发人员而言,自动内存管理就像是一个黑厘子,如果过度依赖于“自动”,那么这将会是一场灾难,最严重的就会弱化Java开发人员在程序出现内存溢出时定位问题和解决问题的能力。此时,了解JVM的自动内存分配和内存回收原理就显得非常重要,只有在真正了解JVM是如何管理内 存后,我们才能够在遇见OutOfMemoryError时,快速地根据错误异常目志定位问题和解决问题。 当需要排查各种内存溢出、内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就必须对这些“自动化”的技术实施必要的监控和调节。
Java中垃圾回收的重点区域?
垃圾回收器可以对年轻代回收,也可以对老年代回收,甚至是全堆和方法区的回收。 其中,Java堆是垃圾收集器的工作重点。 从次数上讲: 频繁收集Young区 较少收集0ld区 基本不动Perm区(或元空间)
垃圾判别阶段算法 在堆里存放着几乎所有的java对象实例,在GC执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有被标记为已经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。 那么在JVM中究竞是如何标记一个死亡对象呢? 简单来说,当一个对象已经不再被任何的存活对象继续引用时,就可以宣判为已经死亡。 1、引用计数算法:对每个对象保存一个整型的引用计数器属性,用于记录对象被引用的情况。 优点:实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟性。 缺点1:它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。 缺点2:每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了时间开销。 缺点3:引用计数器有一个严重的问题,即无法处理循环引用的情况。这是一条致命缺陷,导致在Java的垃圾回收器中没有使用这类算法。 如果就想使用引用计数算法,怎么解决循环引用? 引用计数算法,是很多语言的资源回收选择,例如因人工智能而更加火热的Python,它更是同时支持引用计数和垃圾收集机制。 具体哪种最优是要看场景的,业界有大规模实践中仅保留引用计数机制,以提高吞吐量的尝试。 Java并没有选择引用计数,是因为其存在一个基本的难题,也就是很难处理循环引用关系。 Python如何解决循环引用? 1、手动解除:很好理解,就是在合适的时机,解除引用关系。 2、使用弱引用weakref,weakref是Python提供的标准库,旨在解决循环引用。
?
?
|