范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Java虚拟机GC的根识别堆空间中活跃对象,JVM内部实现优化引入

  GC的根
  垃圾回收的根和虚拟机运行时紧密结合,理解起来并不容易。
  需要回答两个问题:哪些是垃圾回收的根?如何实现标记?
  以JVM为例,JVM为了能执行Java代码,实现了一套完整的编译、解释、执行框架,其中编译是一个独立的模块,执行是另一个模块。
  而GC的根既与执行框架相关,又与编译相关,除此之外,GC的根还与语言特性和JVM的实现相关。
  在JVM中存在两种类型的根: 强根 和 弱根 。强根是GC的真正根,用于识别堆空间中的活跃对象;弱根并非用于识别活跃对象,只是为了支持语言特性(如Java的引用)或者JVM内部实现的优化而引入的。 强根
  强根这个概念相对容易理解,这里使用线程栈来演示这个概念。假设JVM执行一段Java程序,如下所示: int a = 2;
  Object obj1 = new Object();
  Object c = new Object();
  {
  MyObject d = new MyObject(); //假设MyObject已经定义,且MyObject中有一个成
  员变量f指向Object
  d. f = c;
  // 地点一
  }
  // 地点二
  现在来模拟一下JVM执行过程中内存的使用情况,在代码的地点一,内存布局如图2-14所示。
  图2-14 地点一内存布局
  其中图2-14中栈空间的使用通常在编译时就可以确定,堆空间通常是在运行时才能确定。每一个局部变量a、b、c、d在栈中都有一个槽位(slot)与之对应,这样在程序中才能访问到它们指向的对象或者数值。
  这里稍微提示一下,代码d.f = c并不是将栈中c的值赋值给d.f,而是将c指向的堆地址赋值给d.f。
  当代码执行到地点二时,内存布局如图2-15所示。
  图2-15 地点二内存布局
  此时因为变量作用域,变量d在栈中将无法访问(实际上该槽位被其他的变量使用),变量d因为已经死亡,其对应堆中的内存(图中灰色空间)也应该可以被回收重用。
  基于栈变量可以找到堆空间中所有活跃的对象。当然,如果变量d在GC执行时死亡,在活跃对象的遍历过程中并不能知道变量d是否存在过,也无法知道变量d指向的内存空间。整个GC结束后只能得到所有活跃对象所占用的内存空间,所以追踪的GC算法都是管理活跃对象(将活跃对象赋值到新的空间,即复制算法,或者从整个空间中剔除活跃对象后,采用列表的方式管理自由空间),从而达到内存重用的目的。
  当然实现层面可能还有更多细节需要考虑,例如在栈中一个槽位存放的值到底是指向堆空间的变量(即指针)还是一个立即数(在上述代码中变量a就是一个立即数),对于立即数对象,GC并不需要遍历(因为没有在堆空间中分配内存)。但是GC执行时并不知道槽位到底是一个地址还是一个立即数,如果做 不精确 的GC,可以把立即数也"当作"指针,只要立即数在堆空间的访问范围内,也会把对应的内存空间进行标记;如果做 精确 的GC,则必须区分立即数和指针,所以通常需要额外的信息来保存指针信息(例如使用额外的位图来描述栈空间的哪些槽位是指针),在GC执行时借助额外的信息就可以进行精确的回收。
  经研究发现,通常不精确的GC和精确的GC相比,性能会有15%~40%的差距。
  从栈变量作为根的例子可以看出,如果缺少某一个根,则必然会遗漏一些活跃对象,从而导致GC会访问非法内存。所以必须找到所有的强根并且逐一遍历,才能保证垃圾回收的正确性。 Java引用引入的弱根
  Java语言中的引用主要指软引用(soft reference)、弱引用(weakreference)和虚引用(phantom reference)。
  另外,Java中的Finalize也是通过引用实现的,JDK定义了一种新的引用类型FinalReference,其处理和虚引用非常类似。
  引用的处理和GC关系非常密切。在Java语言层面对于不同类型的引用有不同的定义,简单总结如下:
  1)软引用: 声明为软引用的对象在垃圾回收时只有满足一些条件才会进行回收,这些条件程序员可以设置,比如通过参数SoftRefLRUPolicyMSPerMB设置软引用对象的存活时间。
  2)弱引用: 在垃圾回收执行时,如果发现内存不足声明为弱引用的对象就会被回收。
  3)虚引用: 使用虚引用需要定义一个引用队列,虚引用关联的对象在Java应用层面无法直接访问,而是通过引用线程(reference thread,这是一个Java应用的线程,JVM在启动时会生成该线程)处理引用队列来访问。所以虚引用对象的回收依赖于引用队列中的对象是否被执行,如果引用队列中的对象还没有被处理,则不能回收,否则就可以被GC回收。
  4)Finalize: 如果Java的类重载了Finalize()函数,则需要通过Finalize线程(Finalizer Thread,这是一个Java应用的线程,JVM在启动时会生成该线程)处理。定义了Finalize()函数的对象类似于定义了虚引用,如果在GC执行过程中发现Finalize线程尚未执行对象的Finalize()函数,则对象不会被回收,否则对象就可以被回收。
  可以发现Java语言中引用的处理和GC紧密相关。根据是否需要额外的线程执行额外的动作可以分为两类,对于这两类GC过程,处理方法有所不同:
  1)软引用/弱引用: 在GC执行过程中,首先要通过强根扫描所有活跃对象,如果发现对象的元数据属于Java语言中的软引用/弱引用,则需要额外记录下来,在强根遍历结束后再根据GC的策略来决定是否回收引用对象占用的内存空间。
  2)虚引用/Finalize引用: 在GC执行过程中,首先要通过强根扫描所有活跃对象,如果发现对象的元数据属于Java语言中的虚引用或者Finalize引用,则需要额外记录下来,然后将引用类型的对象单独保留起来,当GC结束后,引用线程处理过的对象就可以在下一次GC执行过程中进行回收。注意,定义了Finalize()函数的对象处理在对象生成期间就知道需要进行额外处理,所以生成的对象会自动添加到Finalize引用中。
  从上面的描述中可以看出,当GC处理Java语言的引用特性时,需要额外地对引用对象进行处理,对于软引用/弱引用,在强根扫描结束以后就可以根78据策略进行回收;对于虚引用/Finalize引用,在本次GC时不能进行回收,通常需要在后续的GC过程中才能真正进行回收,且能否执行回收依赖于引用线程/Finalizer线程是否处理过对象,只有处理过的对象才能在后续的GC中被回收,如果对象没有处理过,JVM需要继续记录这些对象,并保持这些对象活跃。而这些对象明显不属于GC回收时识别的活跃对象,但是为了支持引用特性又必须将其记录下来,保持程序运行语义的正确性,所以JVM内部引入了弱根来记录这些对象。 JVM优化实现引入的弱根
  在Java语言的发展过程中,JVM的研究者发现在JVM内部可以优化实现,从而节约内存或者提高程序执行的效率。为了达到这样的目的,JVM内部也需要引入一些弱根来保证程序运行的正确性。
  这里以字符串为例来演示JVM的一个弱根。Java类库中String类提供了一个intern()方法用于优化JVM内存字符串的存储,intern()方法用来返回常量池中的某字符串。其目的是当Java程序中存在多个相同的字符串时可以共用一个JVM的底层对象表示,从而节约空间。代码片段如下: String str1 = new String("abc");
  String str2 = new String("abc");
  str1.intern();
  str2.intern();
  在示例中,str1和str2都执行了intern()方法,JVM在执行时会优化底层的存储,可以简单地理解intern()方法的功能是:在JVM里面使用一个StringTable(使用hash table实现)存储字符串对象,如果StringTable中已经存在该字符串,则直接返回常量池中该对象的引用;否则,在StringTable中加入该对象,然后返回引用。
  str1.intern()执行后,在StringTable中使用hash table存储这个String对象。因为str1对应的字符数组对象并不在StringTable中,所以它会被加入StringTable中。如图2-16所示,图中用圆表示对象(这里我们忽略外部的引用根信息)。
  图2-16 intern()方法执行前后的内存示意图
  当执行str2.intern()时,首先计算str2的hash code,然后用hash code和str2的字符数组对象在StringTable查找是否已经存储了String对象,并且比较存储的String对象hash code与字符串数组是否相同,如果相同,则不需要再次把字符串放入StringTable中了,并且返回str1这个对象。
  JVM在内部使用了StringTable来存储字符串intern的结果,其结构如图2-17所示。
  图2-17 StringTable存储结构图
  通过StringTable的方式方便共享字符串对象,但是会带来回收方面的问题。如果所有的共享变量都死亡,StringTable中的共享对象也应该释放。但什么时候可以回收或者释放StringTable占用的内存呢?在GC执行过程中,当强根遍历完成后,需要再次遍历StringTable,如果发现没有任何相关的引用,则StringTable中的共享对象可以释放,这个时候就可以回收了。可以看出,当GC的强根遍历完成后需要额外针对StringTable遍历来完成一些内存的释放,而StringTable和GC执行过程中对象的活跃性并无任何关系,仅仅是JVM内部设计带来的额外遍历,这样的根也称为弱根。
  从上面的介绍可以看出,对于弱根,如果不进行遍历,则会导致一定程度的内存泄露,但是并不会影响Java程序正确地执行。为了保障GC执行的性能,在新生代回收中通常不回收这类弱根。当然由于JVM内存设计的复杂性,在一些新生代回收实现中也会处理这类弱根,其原因涉及对另外一些特性的支持的影响(例如类回收或者字符串去重等),这里不再展开介绍。 JVM中根的构成
  JVM中根的构成非常复杂,根据程序执行的语义、语言特性的支持及JVM内部优化实现,可以将根划分为Java根、JVM根和其他根。
  Java根用于找到Java程序执行时产生的对象,包括两类,分别为:类元数据对象,主要利用类加载器来跟踪Java程序运行时加载的类元数据对象。
  Java对象,主要通过线程栈帧跟踪Java程序的活跃对象。
  JVM根主要指JVM为了运行Java程序所产生的一些对象,这些对象可以简单地被认为是全局对象。主要有:
  Universe,Java程序运行时需要一些全局对象,比如Java支持8种基本类型,这些基本类型的信息需要对象来描述(基本类型的描述信息作为全局对象是为了性能考虑),这些对象就存放在Universe中。
  Monitor,全局监视器对象,对于Monitor对象主要是用于锁相关,可能存在只有Monitor对象引用到内存空间的对象,所以Monitor是JVM的根之一。
  JNI,JVM执行本地代码时使用API产生的对象,例如通过JNI API在堆中创建对象,这些对象只在JNI API中使用,所以需要单独管理这些对象。
  JVMTI,使用JVM提供的接口用于调试、分析Java程序。使用JVMTI API时也会分配新的对象。
  System Dictionary,JVM在设计类加载时,对于基本的类,比如Java中经常使用的基础类,会通过系统加载器加载这些类,而这些类在运行Java程序一直都需要,所以这些类被单独加载,单独标记。
  Management,是JVM提供的内存管理API,用于JVM内存的统计信息,在使用这些API时需要创建Java对象,所以需要标记。
  AOT,在JDK 9之后引入了提前编译。在AOT的编译过程中会把全局对象和编译优化的代码对象放在可执行文件中,当执行时会用到这些对象,所以在回收时需要标记。
  其他根主要有:
  语言特性的弱引用。
  JVM弱根,例如管理Java中String中intern产生的对象、编译后代码等。
  这些根共同构成了GC根集合,实际上根的确定和虚拟机运行时密切相关,而运行时又非常复杂,限于篇幅,本文无法对根详细介绍,有兴趣的读者可以参考其他文献。
  需要注意的是,对于弱根的处理在不同的GC实现中有所不同,主要原因是弱根通常涉及内部资源的释放,整个流程耗时较多,在一些回收中会把弱根当作强根对待(即不释放弱根相关的内部资源),以加快GC的执行。 本文给大家讲解的内容是Java虚拟机和垃圾回收基础知识:GC的根下篇文章给大家讲解的内容是JVM中垃圾回收相关的基本知识:安全点,解释+编译+本地+JVM内部并发线程进入安全点感谢大家的支持!

BAYRAKTAR杀手伊朗沙赫德与土耳其无人机几十年来,俄罗斯国防部低估了无人机在现代战场上的能力。相反,与我们不同的是,伊朗依赖于无人驾驶飞机的发展,故意复制美国和以色列技术的最佳范例。战争迷雾迄今为止,没有任何证据或具有高何炅介绍郑源超给排面!曾经的网络歌手,为何纷纷成了音乐教授?7月30日芒果台你好星期六,主题是彩铃,所以邀请了一些当年挺红的彩铃歌手。其中就包括了郑源,据说他光一首一万个理由,当年的彩铃下载就超过一亿两千万次。按2元一次计算,那收入就是2。佩洛西专机正向着亚洲方向飞来7月31日,佩洛西乘坐的美国空军公务机(呼号SPAR19)在夏威夷火奴鲁鲁加油,休整了16个小时后,有一次出现在实时航空态势地图中,正朝着亚洲的方向飞来。佩洛西在夏威夷时,连发4条潘粤明与新女友感情稳定?深夜和美女坐豪车同行,女方肤白颜值高饿了吗?戳右边关注我们,每天给您送上最新出炉的娱乐硬核大餐!7月31日,有八卦媒体拍到潘粤明与一位美女深夜坐豪车同行的画面,引发网友热议。据悉,潘粤明和张雨绮主演的鬼吹灯之南海归墟寸头是检验男神的唯一标准说起现在男生流行的发型十有八九是Undercut或者韩式刘海而却有一群美男纸,偏偏特立独行剃去头发,挑战检验男神的唯一标准寸头!无论剃发前男生是什么发型只要换成寸头瞬间阳刚指数爆表像梅西的进4个,像内马尔的助攻3次,0球0助攻的莱万有点急如果说头2场面对皇马和尤文,莱万一时没有穿上合脚的射门靴还算情有可原,那么面对纽约红牛,打飞了半打好机会的波兰中锋多少有些不好意思。哈维打造的全新红蓝三叉戟,登贝莱和拉菲尼亚都找准CBA三消息广东可签强力新援,江苏小外砍39分,黎伊扬绝杀天津大家好呀,我是北柠,各位小伙伴们要养成先赞后看的习惯哦!广东队这个休赛期需要考虑的是下个赛季到底引进什么样的外援,说实话就目前广东队的球员阵容看来,他们依旧有机会冲击总冠军,但是外谁能最快秒杀大龙?男枪2秒排不进前十大家好,这里是布锅锅的游戏新纪录系列节目。你觉得什么英雄才能在最短时间内击杀一条大龙呢?这次的比赛规则十分简单,进入训练模式,在时间到达整数后开始计时,挑战最快击杀一条满血大龙。开为何黄珊珊老打马英九?台名嘴爆不爽国亲合作后,亲民党被吃掉据台媒报道内湖交通议题成为台北市长选战焦点,继台北市长柯文哲与民进党参选人陈时中互杠,台北市副市长黄珊珊日前表示,马英九担任台北市长时,让内湖科学园区工作人数容纳量增加,却没有交通海南喊你来旅游!8月起这类人群游景区门票免费机票打折!海口这些景区在列全国医护人员福利来啦!8月1日至9月30日海南省旅游和文化广电体育厅(以下简称省旅文厅)将开展致敬抗疫英雄让最美逆行者顺风而行邀请全国医护人员惠游海南活动该活动持续两个月,将联合海耿为华被小14岁粉丝倒追,15年后被抛弃,离婚时和女儿抱头痛哭提起耿为华的名字,或许有的人不知道,但是说起他的歌,人们应该不会陌生。风风火火走一回母亲等等,都是耿为华的歌。作为一名军旅歌手,耿为华绝对是够格的,优秀的。只是事业上的顺风顺水,爱
能和我说说复读的坏处吗?能和我说说复读的坏处吗?答,本文特指高三复读。复读的目的是对原来考取的学校不满意,或者原来没有考上,希望再读一年,考取好的学校。这是无可厚非的。但复读也有许多坏处,兹述如下1复读心月薪一万人民币在丹麦属于什么水平?有哪些事去了丹麦才知道的?丹麦人一年只要工作200多天,每天不到7小时,就可以领取人民币40万的年薪。2019年因为工作原因和同事去丹麦呆了两个多月,当时我们从成都的双流机场登机,7月份的成都天气异常闷热,如果让你选择,愿意拿着老人退休金伺候老人,还是愿意选择不要钱什么也不管?这个问题,我就拿我家的情况来说吧!九年前在我母亲去世后不久,父亲就病了,当时我们姊妹五个只有二姐没有上班,父亲也一直和她生活在一起。由于父母亲一直和二姐生活在一起,所以,这次父亲病教师退休金与职称有关系吗?教师的退休金和职称有关吗?回答是肯定的,不管是2014年10月以前退休的教师,还是2014年10月以后退休的教师,退休金都和职称有关。为什么这样说呢?别急着喷,听我慢慢道来。在20月薪税后18k,在深圳属于什么水平?在2018年全国平均年薪排名最高的20个城市中,超过20万元的城市都是一线城市北京位居第一,为25。31万元上海位居第二,为24。42万元深圳位居第三,为23。87万元广州位居第四在北京怎样达到月薪上万。月薪上万的人多吗?朋也观点,月薪上万的确实多,月收入上万的更多,在北京,普普通通的应届毕业生,从零开始干起,三五年后大概率都会月薪过万。哪怕是没学历,没经验的,只要肯吃苦,月薪过万真的可以。虽然现在企业工人熬到60岁退休,到底有多难?相对于机关事业单位,能在企业熬到60岁退休是非常难的。难度指数四颗星。大家好,我是社保专家思之想之,企业工人熬到60岁退休,到底有多难?对于企业工人来说,男职工是60岁退休,女工人社保断缴一个月影响大吗?快乐关羊回答此问题。社保可以断交几个月?社保断缴一个月影响大吗?我国社保缴费规定,养老保险缴费累计年限要达到180个月也就是15年,退休之后才能正常领取养老金,缴满15年后还可以継现在电厂待遇好吗,年薪可以拿到多少?本人就是电厂职工,集控值班猿一只。就职于北方某曾经是大型的火电厂。怎么说呢,我们厂以前也阔过,也算是全国数一数二的电厂了。现在也不算没落,一年也能给集团公司盈利十个亿。虽不算没落,招聘网站上那些找跑船的,工资9千左右,请问这靠谱吗?为什么?靠谱,我现在就在船上,但我一定要告诉你,你要跟招聘的人讲,你上船就只做船上的一个职位,即服务生,别的让你交钱考大证赚好几万的钱那都是忽悠,我为什么要这么说呢?大家看了觉得不错就转给请问公司口头辞退,叫你不要来上班了,你来上班也没工资,等候处理吧,这种情况该怎么办?你这种事,我建议做两手准备。一是听公司的,就等候公司的处理,可能就是结清工资走人吧,前提是你不打算维权二是去劳动部门申请劳动仲裁,讨要工资和赔偿金。我这说的仅仅是一个大概的方略,具