学习笔记摘自https://www.bilibili.com/video/av30023103/?p=67
java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放。
对象空间的分配:使用new关键字创建对象即可
对象空间的释放:将对象赋值null。垃圾回收期负责回收所有“不可达”对象的内存空间。
任何一种垃圾回收算法一般要做两件基本事情
1.发现无用的对象
2.回收无用对象占用的内存空间
垃圾回收机制保证可以将“无用的对象”进行回收。无用的对象指的就是没有任何变量引用该对象。Java的垃圾回收器通过相关的算法发现无用的对象,并且进行清除和管理。
堆中的每个对象都有一个引用计数,被引用一次,计数加1,被引用变量值变为null,则计数减1,计数为0,则表示变为无用对象,算法简单,但是无法识别循环引用
循环引用示例:
程序把所有的引用关系看做一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。emmm,这里的引用应该是全局的寻找的,绝不仅仅是堆或者栈。
----------------------------------------------------------------------------------------------------------------------------------------------------------
垃圾回收线程是回收内存的,而程序运行线程则是消耗(或分配)内存的,一个回收内存,一个分配内存,从这点看,两者是矛盾的。因此,在现有的垃圾回收方式中,要进行垃圾回收前,一般都需要暂停整个应用(即:暂停内存的分配),然后进行垃圾回收,回收完成后再继续应用。这种实现方式是最直接,而且最有效的解决二者矛盾的方式。
但是这种方式有一个很明显的弊端,就是当堆空间持续增大时,垃圾回收的时间也将会相应的持续增大,对应应用暂停的时间也会相应的增大。一些对相应时间要求很高的应用,比如最大暂停时间要求是几百毫秒,那么当堆空间大于几个G时,就很有可能超过这个限制,在这种情况下,垃圾回收将会成为系统运行的一个瓶颈。为解决这种矛盾,有了并发垃圾回收算法,使用这种算法,垃圾回收线程与程序运行线程同时运行。在这种方式下,解决了暂停的问题,但是因为需要在新生成对象的同时又要回收对象,算法复杂性会大大增加,系统的处理能力也会相应降低,同时,“碎片”问题将会比较难解决。
由于不同对象的生命周期不一样,因此在JVM的垃圾回收策略中有分代这一策略。本文介绍了分代策略的目标,如何分代,以及垃圾回收的触发因素。
文章总结了JVM垃圾回收策略为什么要分代,如何分代,以及垃圾回收的触发因素。
分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。
在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关,比如Http请求中的Session对象、线程、Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长。但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会比较短,比如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象甚至只用一次即可回收。
试想,在不进行对象存活时间区分的情况下,每次垃圾回收都是对整个堆空间进行回收,花费时间相对会长,同时,因为每次回收都需要遍历所有存活对象,但实际上,对于生命周期长的对象而言,这种遍历是没有效果的,因为可能进行了很多次遍历,但是他们依旧存在。因此,分代垃圾回收采用分治的思想,进行代的划分,把不同生命周期的对象放在不同代上,不同代上采用最适合它的垃圾回收方式进行回收。
原文链接:https://blog.csdn.net/lufeng20/article/details/7402386
-----------------------------------------------------------------------------------------------------------------------------------------------------------
分代垃圾回收机制,是基于这样一个事实:不同的对象的生命周期是不一样的,因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率,我们讲对象分为三种状态:年轻代,年老代,持久代。JVM将堆内存划分为Eden(伊甸园),Survivor和Tenured(终身的,长期的)/Old空间
所有新生成的对象首先都是放到Eden去。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象,对应的是Minor GC(Minor未成年),每次Minor GC会清理年轻代的内存,算法采取效率较高的复制算法,频繁的操作,但是会浪费内存空间。当年轻代的区域放满对象后,就将对象存放到年老代的区域。
在年轻代中经历了N(默认15)次垃圾回收之后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。年老代的对象越来越多,我们就需要启动Major GC和Full GC(全量回收)来一次大扫除,全面的清理年轻代区域和年老代区域。
用于存放静态文件,如Java类,方法等。持久代对垃圾回收没有显著影响。
1.新创建的对象,绝大多数都会存储在Eden中
2.当Eden满了(达到了一定的比例)不能创建新对象,则触发垃圾回收(GC),将无用对象清理掉,然后剩余对象复制到某个Survivor中,如S1,同时清空Eden区
3.当Eden再次满了,会将S1中不能清空的对象存储到另一个Survivor中,如S2,同时将Eden区中不能清空的对象也复制到S1,保证Eden和S1均被清空。
4.重复多次(默认15次)Survivor中没有被清理的对象,则被复制到老年代Old(Tenured)中.
5.当Old去也满了,则会触发完整的垃圾回收机制(FullGC),之前新生代的垃圾回收成为minorGC
在对JVM调优的过程中,很大一部分工作就是对于Full GC的调节,有如下的原理可能导致Full GC:
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。