安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

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

5月25日 虎狼旗投稿
  GC的根
  垃圾回收的根和虚拟机运行时紧密结合,理解起来并不容易。
  需要回答两个问题:哪些是垃圾回收的根?如何实现标记?
  以JVM为例,JVM为了能执行Java代码,实现了一套完整的编译、解释、执行框架,其中编译是一个独立的模块,执行是另一个模块。
  而GC的根既与执行框架相关,又与编译相关,除此之外,GC的根还与语言特性和JVM的实现相关。
  在JVM中存在两种类型的根:强根和弱根。强根是GC的真正根,用于识别堆空间中的活跃对象;弱根并非用于识别活跃对象,只是为了支持语言特性(如Java的引用)或者JVM内部实现的优化而引入的。强根
  强根这个概念相对容易理解,这里使用线程栈来演示这个概念。假设JVM执行一段Java程序,如下所示:inta2;
  Objectobj1newObject();
  ObjectcnewObject();
  {
  MyObjectdnewMyObject();假设MyObject已经定义,且MyObject中有一个成
  员变量f指向Object
  d。
  地点一
  }
  地点二
  现在来模拟一下JVM执行过程中内存的使用情况,在代码的地点一,内存布局如图214所示。
  图214地点一内存布局
  其中图214中栈空间的使用通常在编译时就可以确定,堆空间通常是在运行时才能确定。每一个局部变量a、b、c、d在栈中都有一个槽位(slot)与之对应,这样在程序中才能访问到它们指向的对象或者数值。
  这里稍微提示一下,代码d。fc并不是将栈中c的值赋值给d。f,而是将c指向的堆地址赋值给d。f。
  当代码执行到地点二时,内存布局如图215所示。
  图215地点二内存布局
  此时因为变量作用域,变量d在栈中将无法访问(实际上该槽位被其他的变量使用),变量d因为已经死亡,其对应堆中的内存(图中灰色空间)也应该可以被回收重用。
  基于栈变量可以找到堆空间中所有活跃的对象。当然,如果变量d在GC执行时死亡,在活跃对象的遍历过程中并不能知道变量d是否存在过,也无法知道变量d指向的内存空间。整个GC结束后只能得到所有活跃对象所占用的内存空间,所以追踪的GC算法都是管理活跃对象(将活跃对象赋值到新的空间,即复制算法,或者从整个空间中剔除活跃对象后,采用列表的方式管理自由空间),从而达到内存重用的目的。
  当然实现层面可能还有更多细节需要考虑,例如在栈中一个槽位存放的值到底是指向堆空间的变量(即指针)还是一个立即数(在上述代码中变量a就是一个立即数),对于立即数对象,GC并不需要遍历(因为没有在堆空间中分配内存)。但是GC执行时并不知道槽位到底是一个地址还是一个立即数,如果做不精确的GC,可以把立即数也当作指针,只要立即数在堆空间的访问范围内,也会把对应的内存空间进行标记;如果做精确的GC,则必须区分立即数和指针,所以通常需要额外的信息来保存指针信息(例如使用额外的位图来描述栈空间的哪些槽位是指针),在GC执行时借助额外的信息就可以进行精确的回收。
  经研究发现,通常不精确的GC和精确的GC相比,性能会有15~40的差距。
  从栈变量作为根的例子可以看出,如果缺少某一个根,则必然会遗漏一些活跃对象,从而导致GC会访问非法内存。所以必须找到所有的强根并且逐一遍历,才能保证垃圾回收的正确性。Java引用引入的弱根
  Java语言中的引用主要指软引用(softreference)、弱引用(weakreference)和虚引用(phantomreference)。
  另外,Java中的Finalize也是通过引用实现的,JDK定义了一种新的引用类型FinalReference,其处理和虚引用非常类似。
  引用的处理和GC关系非常密切。在Java语言层面对于不同类型的引用有不同的定义,简单总结如下:
  1)软引用:声明为软引用的对象在垃圾回收时只有满足一些条件才会进行回收,这些条件程序员可以设置,比如通过参数SoftRefLRUPolicyMSPerMB设置软引用对象的存活时间。
  2)弱引用:在垃圾回收执行时,如果发现内存不足声明为弱引用的对象就会被回收。
  3)虚引用:使用虚引用需要定义一个引用队列,虚引用关联的对象在Java应用层面无法直接访问,而是通过引用线程(referencethread,这是一个Java应用的线程,JVM在启动时会生成该线程)处理引用队列来访问。所以虚引用对象的回收依赖于引用队列中的对象是否被执行,如果引用队列中的对象还没有被处理,则不能回收,否则就可以被GC回收。
  4)Finalize:如果Java的类重载了Finalize()函数,则需要通过Finalize线程(FinalizerThread,这是一个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的底层对象表示,从而节约空间。代码片段如下:Stringstr1newString(abc);
  Stringstr2newString(abc);
  str1。intern();
  str2。intern();
  在示例中,str1和str2都执行了intern()方法,JVM在执行时会优化底层的存储,可以简单地理解intern()方法的功能是:在JVM里面使用一个StringTable(使用hashtable实现)存储字符串对象,如果StringTable中已经存在该字符串,则直接返回常量池中该对象的引用;否则,在StringTable中加入该对象,然后返回引用。
  str1。intern()执行后,在StringTable中使用hashtable存储这个String对象。因为str1对应的字符数组对象并不在StringTable中,所以它会被加入StringTable中。如图216所示,图中用圆表示对象(这里我们忽略外部的引用根信息)。
  图216intern()方法执行前后的内存示意图
  当执行str2。intern()时,首先计算str2的hashcode,然后用hashcode和str2的字符数组对象在StringTable查找是否已经存储了String对象,并且比较存储的String对象hashcode与字符串数组是否相同,如果相同,则不需要再次把字符串放入StringTable中了,并且返回str1这个对象。
  JVM在内部使用了StringTable来存储字符串intern的结果,其结构如图217所示。
  图217StringTable存储结构图
  通过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产生的对象,例如通过JNIAPI在堆中创建对象,这些对象只在JNIAPI中使用,所以需要单独管理这些对象。
  JVMTI,使用JVM提供的接口用于调试、分析Java程序。使用JVMTIAPI时也会分配新的对象。
  SystemDictionary,JVM在设计类加载时,对于基本的类,比如Java中经常使用的基础类,会通过系统加载器加载这些类,而这些类在运行Java程序一直都需要,所以这些类被单独加载,单独标记。
  Management,是JVM提供的内存管理API,用于JVM内存的统计信息,在使用这些API时需要创建Java对象,所以需要标记。
  AOT,在JDK9之后引入了提前编译。在AOT的编译过程中会把全局对象和编译优化的代码对象放在可执行文件中,当执行时会用到这些对象,所以在回收时需要标记。
  其他根主要有:
  语言特性的弱引用。
  JVM弱根,例如管理Java中String中intern产生的对象、编译后代码等。
  这些根共同构成了GC根集合,实际上根的确定和虚拟机运行时密切相关,而运行时又非常复杂,限于篇幅,本文无法对根详细介绍,有兴趣的读者可以参考其他文献。
  需要注意的是,对于弱根的处理在不同的GC实现中有所不同,主要原因是弱根通常涉及内部资源的释放,整个流程耗时较多,在一些回收中会把弱根当作强根对待(即不释放弱根相关的内部资源),以加快GC的执行。本文给大家讲解的内容是Java虚拟机和垃圾回收基础知识:GC的根下篇文章给大家讲解的内容是JVM中垃圾回收相关的基本知识:安全点,解释编译本地JVM内部并发线程进入安全点感谢大家的支持!
投诉 评论 转载

Java虚拟机GC的根识别堆空间中活跃对象,JVM内部实现优GC的根垃圾回收的根和虚拟机运行时紧密结合,理解起来并不容易。需要回答两个问题:哪些是垃圾回收的根?如何实现标记?以JVM为例,JVM为了能执行Java代码,……盛世治官,乱世治民纵观我国历史长河,治官和治民始终是摆在一个国家面前的两道必答题。如何处理好二者之间的关系,度又如何把握,因时因势又该作何转换,执政者每天都在思考这么几个问题。一、古代盛世……助听器能左右耳佩戴吗?助听器有几种类型的,如果是简单的模拟助听器,是不区分左右耳,两侧都是可以直接佩戴的。不过现在主流市场的助听器都是数字助听器,是要测试听损患者的听力损失,根据听力损失和听觉反映调……野生小溪有多危险?千万不要在野外溪流戏水了麦地那龙线虫又名几内亚龙线虫,是唯一主要由饮用水传播的线虫。成虫寄生在人体和多种哺乳动物组织内,会引起麦地那龙线虫病。曾广泛流行于非洲、印度等热带、亚热带地区。图源网络联……美联储持续激进加息加剧欧美经济困境当地时间11月2日,美国联邦储备委员会宣布加息75个基点,将联邦基金利率目标区间上调75个基点到3。75至4之间,这是美联储今年连续第四次加息75个基点,也是美联储今年第6次加……九龙宝剑价值连城,因陵寝盗掘再现世,不吉传说和最终下落成迷?大千视野万象观止中国文物收集,在历史上大多都是以皇家收藏为主,特别是在强盛时期的朝代,他们利用皇权、进贡、金钱等方式来收集各种宝物。乾隆皇帝是最后一个封建盛世朝代,……冷空气来袭!辽宁将迎来两次降水大风降温天气过程央广网沈阳10月16日消息(记者麦丰)记者日前从辽宁省气象台了解到,受较强冷空气影响,10月16日~17日,辽宁大部地区气温将下降8~12,抚顺、本溪、营口、阜新、铁岭地区及康……那个满眼是你的女孩,是怎么被你弄丢的?轻易得到的也要珍惜相信很多年轻的男女都渴望着纯洁的爱情,现在的社会比较混乱,爱情也比较复杂。现在的年轻人都在追求快感,所谓的快感,就是那种很快就确定了关系,却又很快分手的人。也有人认……御真炁,妙养身形,合天地,古今雄风一日三歺养身形,酸甜苦辣品人生。阴晴圆缺曰月情,天地合德万物胜。悲欢离合人生曲,春夏秋冬生机送。气贯斗牛旭彩虹,万里山河自奔腾。经天纬地育生灵,小溪歌唱水传情。蟋夜秋鸣待天明,……中南建设陈锦石未来市场将更规范发展将更稳定焦点财经讯8月30日下午,中南建设(000961。SZ)召开2022年半年度业绩交流会。公司董事长陈锦石、董事兼总经理陈昱含、副总经理兼财务总监辛琦以及董事会秘书梁洁共同出席。……台湾十大爱国人士一:洪秀柱,她是推进两岸交流的代表人物,赞同九二共识,勇敢抵御民进党卖国求荣,认贼作父的罪恶行径,积极推进国家统一洪秀柱女士二、黄智贤,曾表示一国两制是大陆对台湾省……公务员暂发年终奖,有些地区已率先响应,备考生表示不淡定了公务员在近些年来非常的受人追捧,很多大学生大学毕业之后一时不知道何去何从,最终都选择了考公这条路,随着大学生数量的增多,考公的人数自然也相对增加了不少,公务员考试18岁以上35……
信徒3。5亿,影响整个东亚,起源古印度的佛教为何被赶出印度?关注车厂囤货遭零部件供应商示警超额下单或将面临库存反噬相亲恋爱结婚,姑娘们应该怎么做?人死了,灵魂真的又会转世投胎吗回到北宋,地方给中央上供物资如何管理,如果是你当官,你知道吗乡村中小学成绩差如何破解?四川先锋杜海涛抢险前线的关中战士1981年,伊丽莎白二世生日庆典遭遇刺杀,为何中6枪还大难不农村光棍烦恼多,东挪西借买了房,却输给了彩礼,啥时候是个头?5月退休人员养老金暂停发放且每人会发800元过节补贴,是真的监狱多久可以探视一次,每次允许几个人去?达州房价三至五年会降吗?职业病防护设备有哪些抢我的孩子,结果我把人贩子打成重伤,我有错吗?夏植丝瓜种植管理技术支气管扩张发病率如何降低老虎找朋友小学生作文那一次,我错了1099元!云米智能马桶盖Nano2开售内置恒温加热系统巨蟹座男与水瓶星座女三天不下床(天蝎配双鱼三天不下床)朴叙俊加盟漫威?或将与惊奇队长组CP?官方回应无可奉告职场笑话老板顾客和员工的笑话十道基本英文求职面试题问答小米汽车的产品定义假说

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利