纠纷奇闻作文社交美文家庭
聚热点
家庭城市
爱好生活
创业男女
能力餐饮
美文职业
心理周易
母婴奇趣
两性技能
社交传统
新闻范文
工作个人
思考社会
作文职场
家居中考
兴趣安全
解密魅力
奇闻笑话
写作笔记
阅读企业
饮食时事
纠纷案例
初中历史
说说童话
乐趣治疗

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

4月8日 夜如影投稿
  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相比,性能会有1540的差距。
  从栈变量作为根的例子可以看出,如果缺少某一个根,则必然会遗漏一些活跃对象,从而导致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内部并发线程进入安全点感谢大家的支持!
投诉 评论 转载

女生如何提升气质?高品位新款裙子时尚气质你知道女生如何提升气质?当然是靠穿衣搭配啦,利落领部设计,可以显露迷人的锁骨线条。前幅个性趣味的卡通印花,配以拼色设计,个性时尚的同时彰显清新文艺感,非常漂亮!女生如何提升气质……谷爱凌晒斯坦福首学期满分成绩单,网友热评上帝关了她哪扇窗?就在昨天,我的朋友谷爱凌发微博总结了她精彩的2022年:我们一起上了中国新华社体育部最佳十个运动员,美国最大电视台NBC奥运会最佳十大时刻,纽约时报21个最佳运动时刻,CNN年……西瓜和桃子不能一起吃?这些食物相克的说法有科学依据吗?阅读前请点击关注,我们会发送健康的相关文章,让爱健客陪您一起关爱健康资讯食物相克这一说法已经深入人心,因为每种食物的营养成分不一样,搭配在一起吃的时候会发生变化,导致人体……这5款蕾丝拼接连衣裙外穿内搭显瘦又增气质(图)这5款蕾丝拼接连衣裙外穿内搭显瘦又增气质。蕾丝一直都是时尚圈的焦点,唯美的蕾丝拼接连衣裙,让蕾丝更加性感。蕾丝拼接连衣裙的黑色蕾丝,搭配若隐若现的镂空设计,蕾丝拼接连衣裙增添了……我国用载人火箭发射了一颗可重复使用的航天器,这应该是个大家伙航天器大都是一次性的,发射到太空服役一段时间后,过了工作任务基本就报废了。但是在今年的8月5日,我国在酒泉卫星发射中心用长征二号F运载火箭成功发射了一型可重复使用的试验航天器,……短款针织衫外套怎么搭配温暖而不失时尚【短款针织衫外套怎么搭配】短款针织衫外套怎么搭配?在短款针织外套搭配方面也不用顾虑太多,随性如果针织衫以短款为主,短款针织衫外套怎么搭配?跟着小编的脚步一起来看看短款针织衫外套……中长款条纹透视感针织衫帅气优雅针织衫推荐中长款条纹透视感针织衫:帅气优雅针织衫推荐。中长款条纹透视感针织衫有种帅气的感觉,中长款的长度,大气优雅,又充满女人味,中长款条纹透视感针织衫,侧边做了开叉处理,开启朦胧的透视……随笔想念父亲那年的秋天您走了带着我无限的遗憾我知道您一定是去了天堂哪里没有车祸您可以骑着您的摩托车横冲直撞哪里没有官场您还可以继续善良哪里也没有忙……牛仔马甲怎么搭配好看百搭的牛仔马甲穿出性感与优雅牛仔马甲横跨春夏秋冬,一年四季都能穿!一件薄款的牛仔马甲对于服饰搭配的贡献不容小觑,牛仔马甲夏季搭配什么衣服好看呢?牛仔马甲的搭配技巧你会吗?马甲的混搭可以增加整体搭配的层次感……小香风外套的搭配技巧优雅的小香风外套凸显曼妙身姿小香风如今可谓风靡全球,它能轻松表达出女性的优雅与高贵感。自从周迅在国外时装周上穿了小香风外套后,就掀起了一股又一股的小香风风潮!小香风外套的搭配技巧你会吗?小香风外套怎么搭配……为什么锻炼身体是治愈产后风的一味良药呢?前言在某种意义上来说,医生的角色和妈妈的角色类似,妈妈为孩子提供食物和保护,让孩子能够探索世界。医生为病人提供药物和疗愈,让病人能够继续各自的幸福生活。我们都知道生……Java虚拟机GC的根识别堆空间中活跃对象,JVM内部实现优GC的根垃圾回收的根和虚拟机运行时紧密结合,理解起来并不容易。需要回答两个问题:哪些是垃圾回收的根?如何实现标记?以JVM为例,JVM为了能执行Java代码,……
地球怎么了?灭绝的生物陆续出现,这个灭绝80年的生物是焦点1把梳子去眼袋皱纹!每天按揉20下,眼睛好漂亮,阿姨变成小姐金曜石和黑曜石哪个好前者功能更强大条纹阔腿裤怎么搭配衣服条纹阔腿裤配什么上衣好看2019年流行什么碎花裙碎花裙这样选ChatGPT论文优化项目本地搭建(手把手教学)供销社龙头股复牌上演地天板异常交易者被暂停账户交易冰种翡翠价格要看具体质感玛瑙手镯戴哪只手好有这些佩戴讲究项链是黄金还是铂金好?项链买黄金还是铂金艾顿续约创历史,杜兰特想加盟太阳已不可能,杜兰特将何去何从高通联发科三星处理器哪家强?还是iPhone13的A15芯片
知乎高赞:拿到年终奖后马上辞职,厚道吗?一剪梅词牌名古诗词有哪些一剪梅词牌名古诗词介绍绝地求生两周年纪念日,发送游戏纪念道具鸭舌帽学期教学计划欢乐谷是哪里的(欢乐谷属于哪个区)蝴蝶姐姐被骂惨了!遇人不淑爱上渣男,衣品竟然这么好名人名言居里夫人名言人类最美唇形排行看看你的唇形有没有上榜第一最受欢轰轰烈烈的干大事,不如踏踏实实的做好每一件小事沐浴露过了保质期还能用吗我爱家乡的红番薯出生三天的宝宝就会挑肥拣瘦了

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找美丽时装彩妆资讯历史明星乐活安卓数码常识驾车健康苹果问答网络发型电视车载室内电影游戏科学音乐整形