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

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内部并发线程进入安全点感谢大家的支持!

大雄的长城情天镇段长城2022年12月11日(周六)早上7点气温零下19度,我们大同市长城文化旅游协会一行七人,由协会监事张仲秋带领自驾出发,目的地灵丘荞麦茬长城。张仲秋大同市长城文化旅游协会安徽少年儿童出版社桦皮船荣获第十六届精神文明建设五个一工程图书奖桦皮船,薛涛著,安徽少年儿童出版社2022年3月出版近日,由时代出版传媒股份有限公司旗下安徽少年儿童出版社出版的现实主义题材长篇儿童小说桦皮船荣获第十六届精神文明建设五个一工程图书宿迁开放大学荣获宿迁市红色电商示范基地荣誉称号近日,宿迁市委组织部市商务局组织召开全市纺织服装产业链党建工作暨党旗领航电商名城建设推进会,会上宣读了关于通报表扬2022年度红色电商示范基地红色电商标杆企业红色电商创业先锋等先进女子自称被辅警猥亵,后被强制送往精神病院,警方通报难息民愤12月21日,南昌市公安局西湖分局发布的一则警情通报,把过去的一起猥亵事件送上热门,引起了很多网友的关注和热议。这则通报主要说明两点1女子并没有被辅警猥亵2女子确实被送往精神病院,党的二十大精神在基层践行监管为民理念服务新区高质量发展党的二十大报告指出,要紧紧抓住人民最关心最直接最现实的利益问题,增进民生福祉,提高人民生活品质。新区市场监管局以党的二十大精神为指引,树牢监管为民的核心理念,多措并举改革创新,以更梅西拯救阿根廷经济的精神支柱12月18日,梅西率领的阿根廷队击败卫冕冠军法国队,阿根廷人时隔36年再次捧起大力神杯。从梅西凝视到捧起大力神杯,梅西走了8年,梅西夺冠填满职业生涯的遗憾,成为实至名归的球王。虽然关注电影节蓝光少年系列电影导演扬帆海南是电影人的福地新海南客户端南海网南国都市报12月21日消息(记者符彩云沙晓峰吴兴财)12月20日,在第四届海南岛国际电影节举办的儿童电影产业发展论坛上,蓝光少年军校总部影视基地正式落户海南。对青光阴能带我们什么?光阴的故事这首歌想必大家都听过。但有没有认真想过光阴时间能带给我们什么。有的人会说,时光催人老,时间能带给我的只是满脸的皱纹和衰老。其实光阴带给我们皱纹和衰老之前,有没有想过其实时有音乐大神帮忙谱曲吗???80的人小皮球,香蕉梨,马兰开花二十一。二八二五六,二八二五七,二八二九三十一。有那么一群人,名字叫80后,出生在那偏远的小山沟,那里民风很淳朴,没有城市的套路,一日三餐蕃暑配白粥一些最近喜欢上的小短句1。我不是为了爱情把生命搭进去了,而是我遇到了比生命还珍贵的爱情。2。怀着爱意带着虔诚保持温柔追逐星星。3。不要因为廉价的新鲜感放弃长久的陪伴。4。年轻的我们把街灯当做月亮。5。没新的赶考之路上的郑重宣示新的赶考之路上的郑重宣示求是杂志编辑部延安,中国革命的圣地新中国的摇篮。这次和中央政治局常委同志一起来,就是要宣示新一届中央领导集体将继承和发扬延安时期党形成的优良革命传统和作风,
杨馥宇一天1000零花钱,参加变形计后,从夜店女王变成女神舞媚娘她是变形计史上最妩媚的主人公,每天不化个大浓妆绝不出门,小小年纪泡吧蹦迪样样精通,抽烟喝酒样样在行,让父母苦不堪言,她便是有着夜店女王之称的杨馥宇。与参加变形计的许多城市主人安培晋三的死亡值得同情吗?安倍晋三作为日本的前首相,近日被枪杀而亡,但是奇怪的是网上居然有极个别的人居然同情这个家伙,说这家伙也是有家庭的,年级大了值得同情。呵呵1。参拜靖国神社不值得原谅靖国神社是什么地方中芯国际华虹集团合肥晶合集成跻身全球芯片代工十强2022年第一季度全球前十大晶圆代工厂出炉了,与2018年特朗普发起中美贸易战之前晶圆代工厂地位发现可喜变化。中国大陆中芯国际华虹集团合肥晶合集成国内三大晶圆代工巨头均在全球前十之辽宁354。7亿元留抵退税款直达纳税人账户央广网7月9日消息(见习记者麦丰)7月8日,记者从国家税务总局辽宁省税务局获悉,截至6月底,辽宁全省已有354。7亿元增值税留抵退税款直达纳税人账户,是去年全年规模的3。6倍。小微民企扛不住,国企也难熬?第一家被债务难倒的国资房企出现了房地产真的是夕阳产业了吗在近期举办的论坛上,企业家曹德旺表达了对当前房地产的看法,他称房地产要让会的人去做,不会做就不要做,不然像现在欠很多债,害了自己也害了别人。房说君认为,房地突发!大批示威者冲入这国总统府,附近两人中枪!安倍枪击案疑犯最初目标并非安倍!vivo印度119个账户遭冻结周末,来看看都有哪些重要消息!最新消息显示,安倍枪击案嫌疑人山上彻也供认,他最初袭击目标并非安倍晋三,原本想袭击宗教团体的干部,但是他无法做到,所以决定袭击日本前首相安倍晋三。斯里中通客车和巨轮智能的龙头资金跷跷板思维作为一个自由交易者,发帖完全是为了记录自己的操盘思路,修正自己对龙头的理解以及操盘的反思,从而巩固自己的操盘体系,做到稳定盈利即可。但没想到突然之间,多出来这么多粉丝,为了感谢这些普京5次被救,安倍1次就走!同是美女保镖,差别咋这么大?我请客,你吃瓜,关注我理性看社会,带你比普通人更接近真相比心建议先收藏再看哦日本前首相安倍晋三8号遭枪击身亡。事发时的安保情况引发关注。警方不能断言安倍遇袭时安保没问题。这同为众多安倍晋三的美女保镖会不会失业当你们都沉浸在安倍晋三不幸去世的悲痛中时,我却在关心安倍的美女保镖会不会因此失业。虽然目前刺杀安倍的嫌疑人已被控制,但负责他安全的保镖显然是严重失职,尤其是其中一位网红女保镖更是被70岁老人坦言在儿子家里养老之后,我才明白人老了住哪里更舒心导语七十岁的张阿姨,她说自从老伴去世之后,害怕孤独的她就主动提出去儿子的家里养老,在儿子和儿媳妇的首肯之下,张阿姨终于达成心愿,搬到儿子的家里居住。自从张阿姨和儿子一家三口共同生活考基层公务员,在通过遴选到更好的机关工作现实吗?公务员考试对于求职者来说都不会陌生,甚至很多人也在备考公务员考试,希望成为一名公务员,但是,公务员考试的难度也是公认的难,特别是级别越高环境越好的工作单位,考试的难度越大,因此,部