设为首页 收藏本站
查看: 1022|回复: 0

[经验分享] IBM JDK 垃圾收集及内存管理机制

[复制链接]
累计签到:3 天
连续签到:1 天
发表于 2015-10-3 14:49:19 | 显示全部楼层 |阅读模式
  原文出自
  http://www-128.ibm.com/developerworks/java/jdk/diagnosis/142.html
  
  1 简介
  本文档描述从1.2.2到1.4.1 SR1的存储组件(ST)功能。(译者注:根据IBM的说明,本文档也适合JDK 1.4.2)
  存储组件(Storage Component)用来分配堆中的存储空间,这些存储空间定义了对象、数组以及类。每个对象在存储空间中占有一部分存储,如果从虚拟机活动状态中存在到这个对象的引用(指针),这个对象就是可到达的;当虚拟机活动状态不再存在到这个对象的引用,这个对象就被视为垃圾,他占用的存储空间可以被重新使用。当申请重用发生时,垃圾收集器必须进行一些清理工作,以确保该对象所关联的监视器能够被释放回对应的监视器池中。存储组件并不是等同对待所有的对象,比如类对象以及线程对象是在堆的一个特殊空间(Pinned Cluster,固化簇)内进行分配的;在追踪整个堆的时候,引用对象和其派生对象也是被特殊处理的。在4.4章"引用对象"中对于这种特殊情况有详细的阐述。
  1.1 对象分配
  对象分配是由对于某个分配接口的调用来驱动的,例如stCacheAlloc, stAllocObject, stAllocArray, stAllocClass。调用这些接口会在堆上分配一块空间,但是调用时的参数有所不同。stCacheAlloc函数是为小对象的高效分配所设计的,每个线程会预先从堆中申请一块独享的空间,叫做线程本地堆(Thread Local Heap),简称TLH。小对象在这个空间内直接进行分配。一个新的对象从线程本地堆的底部开始分配,由于无需获取堆锁,所以这种分配动作是非常高效的。如果对象较小(当前上限是512字节),那么即使使用stAllocObject和stAllocArray接口,对象也会分配在线程本地堆。
  1.2 可到达对象
  线程执行栈、类内部的静态对象以及本地和全局的JNI引用共同构成了虚拟机的活动状态。虚拟机内部调用的函数会导致在C执行栈上生成一个帧,这些信息用来寻找根对象,从根对象出发来寻找被引用的对象。这个过程会一直重复直到找到全部可到达对象。
  1.3 垃圾收集
  当堆内存空间不足,导致虚拟机内存分配失败时,就会发生垃圾收集。垃圾收集的第一步工作就是找到堆中全部的垃圾,这个工作可以由任何线程的内存分配失败激活,也可以由显式调用System.gc()函数激活。首先,要获取垃圾收集所需的全部锁,这可以保证对于当时拥有临界锁的线程不会被挂起。通过执行管理接口(execution manager, XM)来挂起其他线程,以确保对于调用线程,其他线程的挂起状态是可进入的,这个状态包括在挂起时刻的从顶到底的执行栈以及寄存器状态,以用来追踪对象引用。在此之后,垃圾收集才可以开始工作,包含3个阶段:
  · 标识
  · 清理
  · 压缩(可选的)
  1.3.1标识阶段
  在标识阶段,所有的被虚拟机活动状态引用,或者静态的,或者固化字符串以及被JNI引用的对象都被标识。这个动作创建了JVM引用的根对象,这些根对象可能会依次引用其他对象,因此,标识阶段的第二部分工作就是从根对象出发,扫描其他被引用对象。这两步工作产生一个活动对象集合。
  分配集合(allocbits)中的每个比特位标识堆中的一个8字节段,一旦分配了一个对象,分配集合中的对应比特位会被标识。垃圾收集器开始追踪栈时,首先比较指向堆底和堆顶的指针,确保指针指向的是8字节边界的对象,然后对分配集合中对应的比特位进行标识,表示该指针指向一个活动对象。然后在标识集合(markbits)中对对应的比特位进行标识,表明该对象处于被引用状态。
  最后,垃圾收集器扫描对象的域字段查找被这个对象引用的其他对象,这个扫描过程是准确完成的,因为方法指针存储在第一个字单元,垃圾收集器能够知道对象的类型。在对象链接时(对象第一个实例创建之前),类装载器会创建一个偏移集合,这个偏移集合中记录了对象中引用其他对象的字段偏移位置,垃圾收集器通过访问这个偏移集合找到对应的域及其引用的其他对象。
  1.3.2清理阶段
  标识阶段之后,在标识集合中包含了堆中所有可到达对象的标志。标识集合必须是分配集合的一个子集,清理阶段的工作就是找到这两个集合之间的差集,也就是在那些已经分配但是不再被引用的对象。
  最起初,清理阶段就是从堆底开始扫描,依次访问堆中的每个对象。对象的长度存储在一个字单元中,对于每个对象,垃圾收集器检测对应的分配标识位和标识标识位以定位垃圾。
  现在,使用bitsweep技术无需扫描整个堆,这样就避免了页交换的额外消耗。bitsweep技术直接在标识集合中寻找长的连续的0(未被标识的对象),这段长的连续的0可能表示一段空闲空间。找到这样的序列之后,垃圾收集器检测序列开始前的对象的长度,以检测可以被释放的空闲空间的大小。
  1.3.3压缩阶段
  垃圾收集器将垃圾从堆中移除之后,将剩下的对象向一侧压缩排列,以便移除这些对象之间的空闲空间。由于压缩动作消耗很大,所以应该尽量避免。在4.3.1章对于如何避免压缩有详细的阐述。
  压缩是一个非常复杂的过程,因为句柄已经不再存在于虚拟机中了。如果垃圾收集器移动了某个对象,那么需要修改所有指向这个对象的引用。如果有来自栈的引用,那么就无法确定是这个引用确实是对象引用(有可能是一个浮点数),所以这个对象就不能移动。这种对象临时固定在他原来的位置,并且在头信息中使用对应比特位标识。类似的,在JNI操作的过程中,从JNI引用的Java对象也是固化的,无法移动,直到JNI操作结束。利用mptr低三位设置为0,可移动的对象在两个阶段内被压缩到一起。这3个比特位中一个用来标识对象已经被清理,注意,清理标识位出现在两个地方:link域(即OLINK_IsSwapped)和mptr (GC_FirstSwapped)。这两种情况,都会设置最低的比特位(x01)。
  在压缩阶段的最后,所有线程通过XM恢复运行。
  2 数据区域
  2.1 一个对象
DSC0000.png
  
  图表 1 一个对象
  图表1是堆中一个对象的布局
  · size + flags (大小和标识)
  size + flags在32位架构上占4字节,在64位架构上占8字节,主要目的是用来存储对象的大小。由于对象都是从8字节边界开始,并且对象大小可以被8整除,最低3个比特位不被使用,垃圾收集器用来作为标识位以标识对象的不同状态。另外,由于对象大小是有限的,所以最高2个比特位也用来作为标识位(mptr也是8字节边界的)。
  size + flags 中的标识位如下:
  § 第1位有多个用途。在清理阶段作为清理标识,在压缩阶段也会用到它。第1位还是多次固化标识位,用来标识该对象被多次固化。在垃圾收集的一个周期,多次固化标识位被清除,用作其他用途,然后恢复
  § 第2位是dosed位。如果从栈或者寄存器有到某个对象的“引用”,就会在dosed位进行标识。这里“引用”是指在本次垃圾收集周期不能移动该对象,因为垃圾收集器无法确定该“引用”是一个真正指向对象的引用还是碰巧只是一个和对象句柄值相等的整数
  § 第3位是固化标识位。固化的对象就是从堆之外有指向这个对象的引用,例如线程和类对象。此类对象无法移动
  § 32位架构的第31位或者64位架构的第63位是锁(flat lock)竞争位,被锁管理模块(locking, LK)使用
  § 32位架构的第32位或者64位架构的第64位是哈希标识位,表示一个对象已经返回了哈希值。因为对象的哈希值就是对象的地址,如果垃圾收集器移动了这个对象,需要维护这个值
  · mptr
  mptr槽位在32位架构上占4字节,在64位架构上占8字节,mptr是8字节边界的(译者注:原文为The mptr slot is grained on an 8-byte boundary, not the size + flags. 不知道如何翻译才是准确的),功能为以下两种之一
  § 如果对象不是数组,mptr指向类方法表,垃圾收集器据此找到类信息。通过这种方式,垃圾收集器知道对象是从哪个类实例化的。类的方法表和类本身的信息由类加载器组件(class loader, CL)分配,但是不存储在堆空间
  § 如果对象是数组,mptr是数组内条目的计数
  · locknflags
  locknflags槽位在32位架构上占4字节,在64位架构上占8字节,但是只有低4字节被使用。主要作用是用来保存锁信息。另外还包含3个标识比特位
  § 第2比特位是数组标识。如果对象是数组,则该标识位设置为1,mptr槽位保存数组中对象的个数
  § 第3比特位是哈希和移动标识位,如果这个标识位被设置为1,表明该对象被移动过,可以在对象在移动之前的位置找到其哈希值
  § (译者注:在图表1中并未画出locknflags槽位,原文如此,笔误?)
  · 对象数据
  这里是开始记录对象数据的位置
  size + flags, mptr以及locknflags一起称为对象头信息
  2.2
DSC0001.png
  
  图表 2 堆
  图表2是堆的示意图。堆是虚拟机在初始化时从操作系统申请的一段连续的内存空间。堆底是堆的开始地址,堆顶是堆的结束地址,堆上限是堆中当前使用部分的结束地址。堆上限可以扩展和收缩。-Xmx参数限制了从堆底到堆顶的最大值,如果未设置,默认值如下:
  · Xmx
  § Windows: 物理内存的一半,最小16MB,最大2GB-1
  § OS/390 和 AIX: 64MB
  § Linux: 物理内存的一半,最小16MB,最大512MB-1
  · Xms
  § Windows, AIX, Linux: 4MB
  § OS/390: 1MB
  2.2.1设置堆大小
  对于大多数应用而言,默认的设置即可满足需求。在运行时,堆会自动扩展到一个稳定的状态,保证在任何时刻堆中活动对象占堆大小的70%,在这种状态下,垃圾收集的频率和暂停时间都是可以接受的。
  对于某些应用而言,默认参数可能无法保证应用的良好运行,下面列出可能出现的问题以及应对策略。使用verbosegc可以监控堆的使用情况。
  · 在堆到达稳定状态之前,垃圾收集发生的过于频繁
  使用verbosegc检测堆到达稳定状态时的大小,然后设置-Xms参数等于该大小
  · 堆已经扩展到最大限制,但是堆占用率仍然高于70%
  增加-Xmx的设置,以使得堆能够扩展到一个能够保证占用率不高于70%的大小。但是需要注意的是,要保证堆的内存都是从物理内存占用,避免出现页交换
  · 堆占用率在70%,但是垃圾收集发生的频率过高
  修改-Xminf参数。默认是0.3,表示堆要通过扩展保证有30%的空闲空间。例如,设置该参数为0.4,会降低垃圾收集发生的频率
  · 暂停时间过长
  尝试使用-Xgcpolicy:optavgpause参数。在堆的占用比增高的情况下,该参数能够保证垃圾收集时间的稳定,但是会带来大约5%的吞吐量的下降,具体视应用而定
  另外,还有一些小提示:
  · 确保堆不会发生页交换(即堆内存全部从物理内存中获取)
  · 避免使用finalizer。你不能确保finalizer执行的时机,这样会带来一些问题。在verbosegc的输出中,可以看到是否已经执行了finalizer。如果确实需要使用finalizer,需要注意以下三个关键点
  § 不要在finalizer方法中创建新的对象
  § 不要依赖finalizer来释放一些本地资源
  § 不要在finalizer方法中进行长时间执行的或者阻断式的动作
  · 避免压缩。verbosegc的输出中可以显示是否进行了压缩动作。通常,压缩动作是由于大块内存的分配引发的,所以,要分析应用中对于大块内存的需求,比如,一个大的数组对象,可以将其拆分成多个小片段
  2.3 分配集合和标识集合
DSC0002.png
  
  图表 3 堆以及分配集合和标识集合
  图表3是堆、分配集合和标识集合的示意图。这两个比特位集合标记了堆中对象的状态。因为堆中对象都是8字节边界的,所以每个比特位对应1个8字节段,这两个比特位集合的大小为堆大小的1/64。
  一旦在堆中分配了一个对象,在分配集合中对应对象开始地址的比特位被设置为1。分配集合只是标识了对象被分配,但是无法得知对象是否是活动的。在垃圾收集的标识阶段,标识集合中对应的比特位会被设置,以表示对象是活动的。图表4表示堆中的2个对象,分配集合中对应比特位都被设置为1.
DSC0003.png
  
  图表 4 堆中一些对象
  在标识阶段,Object2是被引用的,Object1是未被引用的,所以在标识集合中对应
  Object2的比特位被设置为1,在清理阶段,Object1会被垃圾收集。
  2.4 系统堆
DSC0004.png
  
  图表 5 系统堆
  系统堆中包含的对象是跨越整个虚拟机生命周期的对象,通常这些对象是系统级的类对象、可共享的中间对象以及应用级对象。垃圾收集器不会收集系统堆中的对象,因为这些对象在整个虚拟机生命周期内都是可达到的,或者是应用需要共享的一些对象。图表5是系统堆的示意图。系统堆不是连续的存储空间,而是由多个存储段构成的链。系统堆的初始大小在32位架构上是128KB,在64位架构上是8MB。如果系统堆被对象充满,虚拟机会重新分配一块空间,并且加入到系统堆的链表中来。
  2.5 空闲链表
DSC0005.png
  
  图表 6 空闲链表
  图表6表示空闲链表,链表的头是一个全局的指针,指向空闲链表的第一个存储段。空闲链表的每个存储段都有一个大小字段和一个指向下一个空闲存储段的指针,链表的最后一个空闲存储段的Next为空指针。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-122228-1-1.html 上篇帖子: 世界十大科技品牌 IBM与微软占据前二名 下篇帖子: 仿IBM首页焦点图,缩略图大图,带文字
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表