详解JVM内存管理与垃圾回收机制5

  • 时间:
  • 浏览:0
  • 来源:大发彩神幸运飞艇_大发神彩幸运飞艇官方

关于引用,还有几次 多多重要的知识点没办法 涉及,可是引用队列ReferenceQueue,在参考资料的文章含有更详细的讲解,可能我来写语录,可是见得比亲戚大伙儿好,可是就省略。

一种策略均含有你这名 函数,它用于判断算是还都可以不能清理引用对象:interval大于_max_interval,就回收该对象。现在就剩下几次 多多疑问了,interval表示哪此,怎样得来的?再回顾一下SoftReference类的定义,重点关注clocktimestamp几次 多多属性。

通过源码还都可以还都可以不能知道,在构造WeakHashMap的Entry时,会将key关联到几次 多多弱引用上,GC占据 时,Map的Key会被清理掉,但Map的Value仍然是强引用,它会在WeakHashMap的expungeStaleEntries()土办法中被移除数组(Entry[]),这时Value关联的强应用被干掉,即占据 可回收情况汇报。

在Java语言中,除了基础数据类型的变量以外,一点的都是引用类型,指向各种不同的对象。在前文亲戚亲戚大伙儿也可能知道,Java中的引用还都可以还都可以不能是认为对指针的封装,你这名 指针中存储的值代表的是另外一块内存的起始地址(对象所在内存的首地址)。在你这名 定义下,几次 多多对象还都可以还都可以被引用和没办法 被引用一种情况汇报,当对象没办法 被引用的事先,即被JVM回收,但你这名 设计太大能满足所有的应用场景,比如,缓存:在内存还足够时,希望哪此对象老会 保持在内存中,而可能内占据 GC后还是非常紧张,则还都可以还都可以不能丢弃一点对象。可是,在JDK1.2事先,Java对引用的概念进行扩充,将引用分为:强引用、软引用、弱引用和虚引用4种。怎样理解这4种引用类型,它们之间有何区别?具体的应用场景有哪此?

同样地,从几次 多多简单的示例着手:

当几次 多多对象还都可以还都可以不能通过普通引用链 (不包括引用对象) 从根集访问时,则表示该对象强可达。换一种说法,强可达对象还都可以还都可以不能不通过各种引用直接访问到。延伸开来,可能达到对象的唯一路径上涉及大慨几次 多多软弱引用对象,则称该对象是软弱可达。最后,虚可达对象可是没办法 强、软、弱引用关联,可是 finalize 过了,还都可以还都可以幻象引用指向它的类似于对象。你这名 定义稍微有点硬绕,下面的示意图应该还都可以还都可以不能帮助你理解。

弱引用的内存结果示意图与软引用类似于,这里就不在 使用示例代码来说明,具体还都可以还都可以不能参考前面的内容。

可能本文都是专门分析WeakHashMap源码的文章,可是,对于WeakHashMap的实现,点到即止,在这儿只还都可以不能理解WeakHashMap的Key会在GC时被回收,进而回收其对应的Value。关于WeakHashMap源码的文章,亲戚亲戚大伙儿还都可以还都可以不能自行搜索,网上可能有可是啦,这里推荐: Java WeakHashMap 源码解析,推荐它,主可是可能文章对为哪此要使用引用队列ReferenceQueue讲得很透彻。

限于篇幅和侧重点的因为 ,本文在介绍应用场景的事先,主要着眼于SoftReferenceWeakReference,而对于虚引用的应用场景并未作太大的说明,可能你感兴趣语录,还都可以还都可以不能阅读Java Reference Objects 的最后几次 多多小节,它使用虚引用定制了几次 多多资源分类分类整理器用于在释放数据库连接的共同,释放占用的资源。

那虚引用到底有哪此作用?实在虚引用主要被用来跟踪对象被垃圾回收的情况汇报,当目标对象被回收事先,它的引用会被贴到 几次 多多ReferenceQueue对象中,通过查看引用队列中算是含有对象所对应的虚引用来判断它算是即将被垃圾回收,从而采取行动。可是,在是创建虚引用的事先,它还都可以不能传入几次 多多 ReferenceQueue 对象,比如:

可能亲戚亲戚大伙儿可能想到了,WeakHashMap中缓存的数据实在活不了多久的,有点硬是GC非常频繁的场景下,没两下,缓存的数据就不在 ,又得重新加载,那它作为缓存的意义何在?实在,单纯的作为缓存语录,可能有SoftHashMap貌似更大慨一下,毕竟当内存够用时,太大希望缓存被GC掉。实在,WeakHashMap应用在更为简化的场景,比如下面的代码:

最后的最后,下一篇会语录GC Roots,感兴趣的同学还都可以还都可以不能继续关注。也顺便撘一句,还都可以还都可以不能直接关注我的微信公众号:「一纸代码」,第一时间阅读最新的文章。

软引用的内存内控 示意图如下所示。你这名 情况汇报下,实在堆中对应的实例对象可能没办法 强引用指向它,但softRef作为强引用指向referent,而referent则指向SoftRefObject type object,看起来堆中的对象还是被强引用关联着,JVM到底是怎样回收这次责内存的呢?

前面亲戚亲戚大伙儿可能提到的这4种引用类型之间的区别主要体现在对象的不同可达性级别以及对垃圾分类分类整理器的影响。因而,引用还都可以还都可以不能认为是Java提供的一种人为干预GC的手段之一。

简单说来,在Client VM模式下,使用LRUCurrentHeapPolicy策略,而Server VM模式下使用LRUMaxHeapPolicy策略,你这名 种生活策略有何区别?注意底下的源码,在setup_policy函数中,调用了不同策略的setup函数,接下来,重点关注你这名 种生活策略的setup函数:

在内存足够的情况汇报下,以上多线程 将输出:

最后,这仅是几次 多多示例而已,提供另外几次 多多应用场景和处置疑问的思路,并都是建议亲戚亲戚大伙儿在操作JDBC还都可以不能使用软引用。

WeakHashMap的另外几次 多多应用场景可是ThreadLocal,考虑篇幅这里就不再讲解,亲戚亲戚大伙儿还都可以还都可以不能参考:这才是 Thread Local 的正确原理与适用场景。但文中没办法 考虑到的几次 多多场景:在线程 池下的ThreadLocal实在占据 内存泄漏,供亲戚亲戚大伙儿思考。

最后总结下,-XX:SoftRefLRUPolicyMSPerMB还都可以还都可以不能影响软引用的存活时间,在一点因素不变的情况汇报下,VM参数的值越大,软引用对象存活越久,同样地,可能应用已使用堆内存不变的情况汇报下,设置的堆内存越大,软引用对象也存活的更久。

这段代码在大次责情况汇报下,都能很好的运行,但它有几次 多多小的占据 问题:可能查询返回一百万行而你没办法 可用内存来存储它们会占据 哪此? 现在使用软引用在完善底下这段代码:

弱引用的几次 多多应用场景可是缓存,老会 使用的数据内控 为WeakHashMap。WeakHashMap与一点Map最主要的区别在于它的Key是弱引用类型,每次GC时,WeakHashMap的Key均会被回收,而后,其Value也会被回收,简单的看下其具体的实现:

一点优化建议:不使用的对象应手动赋值为null,有有助于于GC更早回收内存,减少内存占用。

弱引用的速度比软引用更弱一点,当垃圾分类分类整理器工作时,无论当前内存算是足够,都是回收掉只被弱引用关联的对象。它一般用于维护一种非强制的映射关系,可能获取的对象还在,可是用它,可是就重新实例化,可是,可是缓存框架均基于它来实现。

JVM在每次GC都是更新clock,而在调用get土办法会更新timestamp的值为clock,这两者之差,可是你这名 软引用对象距离上次GC时老会 没办法 被使用的时间,即上文中的interval(时间间隔),可能你这名 时间间隔大于_max_interval,说明你这名 软引用可能被废弃足够长的时间,认为是还都可以还都可以不能被回收的,这也跟策略名称中的LRU相吻合。

现在亲戚亲戚大伙儿来讨论下,这条优化建议算是合理?首先,请思考几次 多多疑问,内存回收的早晚,对应用的影响很大吗?即使赋值为null,内存就立即被回收啥随后?其次,强引用obj是在栈空间中分配内存,当土办法执行完成后,栈帧弹出,所占用的内存被回收,这事先可能没办法 引用指向堆中的对象。综上,绝大多数事先土办法的执行都耗时很短,可是赋值为null到底又还都可以把GC回收的时间点提前几次呢?相信亲戚亲戚大伙儿会有我本人的答案,当然,这里并都是说这条建议毫无意义,可是希望亲戚亲戚大伙儿还都可以还都可以不能思考其应用场景,更无需把它当做十根普遍适应的优化建议。

代码中obj为强引用,指向堆中几次 多多StrongReferenceObject类型的实例对象,当给obj赋值为null事先,让我是什么强引用指向null,没办法 从前堆中的实例对象即还都可以还都可以不能被GC回收,简单的内存示意图如下所示。

所谓强引用,可是亲戚亲戚大伙儿最常见的普通对象引用,类似于Object obj = new Object()类似于的引用,否则还有强引用指向几次 多多对象,垃圾分类分类整理器永远无需回收你这名 对象。对于几次 多多普通的对象,可能没办法 一点的引用关系,否则超过了引用的作用域可能显式地将相应的(强)引用赋值为 null,可是还都可以还都可以不能被JVM回收的,当然具体回收时机还是要看垃圾分类分类整理策略。来看几次 多多简单的例子:

虚引用也被称为暗影 引用,它是最弱的一种引用关系。几次 多多对象是算是虚引用的占据 ,详细无需对其生存时间构成影响,也无法通过虚引用来取得几次 多多对象实例。也可是说,通过其get()土办法得到的对象永远是null。

JVM在进行垃圾回收的事先,首先会遍历引用列表,判断列表中每个软引用中的referent算是存活 (存活的条件是referent指向的对象不为空且被GC Roots可达),可能对象还活着,不进行任何处置,可能对象已死,则尝试回收该对象。这里还有几次 多多疑问,通过前面亲戚亲戚大伙儿知道,软引用会在内存占据 问题时被回收,那JVM是怎样判断内存算是丰厚,其标准是哪此?

所有引用类型,都是抽象类java.lang.ref.Reference的子类,它提供了get() 土办法,其次责代码如下所示。其中referent指向具体的实例对象,可是,可能referent指向的对象还没办法 被回收,都还都可以还都可以不能通过 get 土办法获取原有对象。这因为 ,利用软引用 (弱引用也类似于,下文不再说明),亲戚亲戚大伙儿还都可以还都可以不能将访问到的对象,重新指向强引用(obj=softRef.get()),也可是人为的改变了对象的可达性情况汇报。

通过代码中的注释,应该还都可以很清楚的理解,一种不同策略的区别,而计算得到的_max_interval有哪此作用?亲戚亲戚大伙儿再看:

所有的对象都还都可以还都可以不能有几次 多多finalizer,你仅还都可以不能在对象中定义如下的finalize土办法:

而整个过程中,内存分配都集中在几次 多多地方:调用next()和将行数据存储在我本人的列表中。调用next()时,ResultSet通常会检索含有多行数据库数据的大块二进制数据,以判断数据算是取完。当还都可以不能存储数据时,调用getObject()土办法提取数据并包装成Java对象,可是在扔到列表中。

前面亲戚亲戚大伙儿提到过,还都可以还都可以不能利用软引用来实现缓存,比如一点图片缓存框架中,均多量使用到软引用。可能软引用和弱引用均还都可以还都可以不能应用在缓存的实现,因而,具体的实现原理我贴到 下文弱引用的次责详细说明。这里亲戚亲戚大伙儿介绍软引用的另外几次 多多应用场景:内存熔断。

你看懂这段代码啥随后?是都是跟JVM堆的划分有一点点类似于?这实在是几次 多多热点缓存的实现方案,一段时间事先,老会 使用的缓存就会在eden你这名 Map中,而不常用的缓存就会逐渐被清理。在事先,可能让我来设计热点缓存的实现方案,可能会想可是方案,但不可处置的,会写非常多的代码,但使用WeakHashMap,就变得非常的简单了。

关于文件句柄的相关内容可参考附录的资料1

还都可以不能注意的是,ResultSet太大会直接获取所有的查询结果,一般会通过fetchSize土办法来设置每次返回的行数。

在日常开发中,可是地方都还都可以不能做一点清理的工作,finalize()看起来是几次 多多不错的土办法,但亲戚亲戚大伙儿却很少使用它,甚至在业界,finalize()也被证明是一种非常不好的实践,主可是可能:

熔断机制来源于电力行业,当电流超过规定值时,产生的热量使溶体熔断,断开电路以达到保护电路的目的。在分布式系统中也多量运用熔断机制,以实现快速失败,处置服务间调用的雪崩效应。而这里所讲的内存熔断也类似于,当应用多量使用内存时,容易造成内存溢出错误,甚至多线程 崩溃,你这名 情况汇报下,还都可以还都可以不能使用软引用来处置OutOfMemoryError,以实现自我保护的目的。

从JDK1.2起,Java对对象的生命周期进行了扩充,除了强可达阶段 (如上图所示),另增加了几次新阶段:软可达弱可达虚可达(幻象可达)

另外值得注意的是,实在 SoftReference, WeakReference 以及 PhantomReference 的构造函数都还都可以还都可以不能接收几次 多多 ReferenceQueue 对象。当 SoftReference 以及 WeakReference 被清空的共同,也可是 Java 垃圾回收器准备对它们所指向的对象进行回收时,调用对象的 finalize() 土办法事先,它们自身会被加入到你这名 ReferenceQueue 对象中,此时还都可以还都可以不能通过 ReferenceQueue 的 poll() 土办法取到它们。而 PhantomReference 还都可以还都可以当 Java 垃圾回收器对其所指向的对象真正进行回收时,会将其加入到你这名 ReferenceQueue 对象中,从前就还都可以还都可以不能追综对象的销毁情况汇报。

当进行哪此操作的事先,可能发现内存占据 问题,GC会回收到列表占用的内存,这事先在通过软引用获取列表对象,得到的可是null。当上层得到自定义的异常时,还都可以还都可以不能进行相关的处置:再次检索可能减少获取数据的行数。还都可以不能注意的是,这里的列表使用的是LinkedList而都是ArrayList,这是可能ArrayList在扩容的事先会创建新的数组,占用更多的内存。

当软引用对象被JVM标记为可回收情况汇报时,仍然还都可以还都可以不能通过get土办法,让其重新被强引用关联,这事先就还都可以不能JVM进行第二次确认,以确保正在使用的对象无需被回收,这也是次责对象真正死亡大慨还都可以不能经历两次标记的因为 ( 相关内容在详解JVM内存管理与垃圾回收机制2 - 何为垃圾 - 简书 )。

对象的几种可达性情况汇报还都可以还都可以不能按照如下示意图进行流转,还都可以还都可以不能看一遍,图中一点地方是双向箭头,这因为 ,亲戚亲戚大伙儿还都可以还都可以不能人为地改变对象的可达性情况汇报。具体的因为 ,亲戚亲戚大伙儿会在下文详细说明。

图中A对象,实在它被弱引用对象B引用,但可能根集直接引用它,可是根集到A对象强可达,同样的根集到对象B、C也是强可达。而对象D、E直接或间接地仅被弱引用对象引用,可是根集到D、E弱可达。

JVM在回收软引用的事先使用了一种不同的策略,具体亲戚亲戚大伙儿来看下源码:

最后,整个文章的基本逻辑还是挺清楚的,但后期校对的事先,发现有遗漏一点知识点,就直接补上了,可是,可能读起来有感觉到别扭语录,请见谅。

在Java中,当对象占据 没办法 被引用的情况汇报下,一段时间后,其内存将被垃圾分类分类整理器回收。然而,内存并都是唯一还都可以不能清理并回收的资源。比如,当创建几次 多多FileOutputStream对象时,会从操作系统分配几次 多多文件句柄,用于文件操作 (文件句柄属于OS资源)。当你这名 流不在 被引用且即将关闭时,你这名 文件句柄会占据 哪此?答案就在finalize()中,你这名 土办法会在垃圾分类分类整理器回收对象事先由JVM来调用。在FileOutputStream对象中,finalize()会关闭文件输出流、释放句柄、刷新缓冲区以确保所有的数据被正确的写入磁盘文件。

几次 多多对象的生命周期还都可以还都可以不能简单的概括为:对象首先被创建,可是初始化,被使用,接着没办法 一点对象引用它(不可达),这事先,它还都可以还都可以不能被垃圾分类分类整理器回收,最终它被回收掉。简单的示意图如下所示,其中,阴影次责便是该对象的强可达 阶段。

回想刚现在刚开使学习JDBC的事先,你一定写过如下代码,它使用几次 多多通用的土办法处置ResultSet并返回几次 多多List<Map>

软引用一般用于描述一点有用但非必需的对象,它相对强引用来说,引用的关系更弱一点。当JVM认为内存占据 问题时,才会去尝试回收软引用指向的对象,可能回收事先,还没办法 足够的内存,才会抛出内存溢出错误。可是,JVM会确保在抛出内存溢出错误事先,回收软引用指向的对象。软引用通常用来实现内存敏感的缓存,当有足够内存时,保留缓存,反之则清理掉次责缓存,从前在使用缓存的共同,尽量处置耗尽内存。

来看代码,首先创建几次 多多强引用obj指向堆中几次 多多SoftRefObject实例对象,可是亲戚亲戚大伙儿创建几次 多多软引用,软引用中的referent指向堆中的SoftRefObject实例,其内存内控 示意图如下图的上半次责。当亲戚亲戚大伙儿加带强引用时,这事先obj指向的对象是还都可以还都可以不能被内存回收的,当内存丰厚时,亲戚亲戚大伙儿还都可以还都可以不能通过get()土办法,得到堆中的实例对象,其内存示意图如下图中的下半次责。