分享
 
 
 

IBMJava如何做到高性能GC的实现内幕

王朝java/jsp·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

IBM JVM的GC分为三个步骤,Mark phase(标记),Sweep phase(清扫),Compaction phase(内存紧缩). 在了解这些过程之前,我们先看一下IBMJava中的对象的Layout和Heap lay out 一个Java对象在IBM vm中的结构如下

1.size+flags

2.mptr

3.locknflags

4.objectdata

size+flags

这是一个4byte的slot(32 平台)。这个slot的主要功能就是描述对象的尺寸。由于IBMJava中的对象都是以8byte的倍数分配的,因此对象的尺寸其实就是真实尺寸/8存放在4byte的slot中。另外在这个slot的低三位是保留字段起到标记对象的作用。他们分别为 bit1:swapped bit,这个交换位被用于Compaction phase即内存紧缩阶段使用。同时 这一位在标记堆栈溢出的时候(mark stack overflow)也被用于标记NotYetScanned状态. bit2:dosed bit.这个位用于标示这个对象是否被某个堆栈或者寄存器reference到了。

如果这个标志被至位则这个对象就不能在当前的GC cycle中被删除。而且如果某个reference指向的内存不是一个真实的reference比如是一个简单的float 或者integer变量但是它的值恰巧就是Heap中某个Object的地址的时候,我们就不能修改这个refernece。这种对象的bit2也被置为1。bit3:pinned bit。标记一个对象是否是一个一个钉扣对象(PINNED object)。一个Pinned Object也不能被GC删除,因为他们可能在Heap之外被reference到了。典型的一个例子就是Thread,还记得我上面说的僵死县城么?它不能被删除的道理就是这个。另外一种PinnedObject就是 JNI Object,即被本地代码使用的对象。

Mptr:

在32平台上也是4byte的slot。Mptr有两个功能,

1。如果mptr不是一个数组,则Mptr指向一个方法块(method block),你可以通过这个method block来得到一个类块(class block)。这个类块,告诉你这个Object是属于哪个class的实例。method block和class block由Class Loader分配,而不是heap在heap中进行分配

2。如果mptr是一个数组(Array),mptr包含了这个对象中,数组的元素个数。 lockflags

在32平台上也是4byte的slot,但是这个slot只有低4位被用到。

bit2:是array flag.如果这个位被置位,那么这个对象就是一个数组同时mptr字段就包含了数组的元素个数。

bit4是hashed和moved bit.如果这个位被置位,那么他就告诉我们这个对象在被hashed以后被删除了。

Object Data:

就是这个对象本身的数据

Heap layout:

heap top

heap limit

heap base

heap base是heap的起始地址,heap top是heap的结束地址。heaplimit 是当前程序使用的那段heap可以进行扩展和收缩的极限。你可以用-Xmx参数在java运行的时候对heap top和heap base进行控制。

Alloc bits 和 mark bits

heap top allocmax markemax

heap limit alloc size marksize

heap base

上面这个结构描述了heap和alloc bits 以及,markbits之间的关系。allocbits和markbits都是元素为1个bit的vector。他们与heap有同样的长度,下面是两个对象被分配以后在heap和两个vector中的表现

heaptop allocmax markmax

heaplimit allocsize marksize

object2top

.

.

object2base object2allocbit object2markbit

object1top

.

object1base object1allocbit

如上面的结构,如果一个对象在heap被alloc出来,那么在allocbits中就标示出这个对象的起始地址所在的地址。allocbits中只标记起始地址。但是这个过程告诉我们这个对象在那里被创建,但是不告诉我们这个对象是否存活。当在mark phase中如果某一个对象比如object2仍然存活,那么就在markbits中对应的地址上标记一下The free list

IBM jvm中的空闲块用用一个free list链标示。如图

freechunck1 freechunck2 freechunckn

size size size

next-------------next---.........next---NULL

freeStorage freeStorage freestorge

有了这些基本概念我们来看看Mark phase的工作情况

MarkPhase

GC的Mark phase将标记所有还活着的对象。这个标记所有可达对象的过程称为tracing。Jvm的活动状态(active state)是由下面几个部分组成的。1.每个线程的保存寄存器(saved registers)2.描述线程的堆栈3.Java类中的静态元素3.以及局部和全局的JNI(Java Native Interface)引用。在Jvm中的方法调用都在C Stack上引发一个Frame。这个Frame包含了,对象实例,为局部变量的assignment结果或者传入方法的参数。所有这些引用在Tracing过程中都被同等对待。实际上,我们可以把一个线程的堆栈看城一系列4-bytes slot的集合,然后对每一个堆栈都从顶向下对这些slot进行扫描。在扫描的过程中都必须校验每个slot是否指向heap当中的一个真实的对象。因为在前面我就说过,很有可能这些slot值仅仅是一个int或float但是他们的值恰巧就等于heap中的一个对象地址。因此在扫描的时候必须相当的保守,扫描的时候必须保证所有的指针都是一个对象,而且这个对象没有在GC中被删除。只有符合下面条件的slot才是一个指向对象的指针。1.必须以8-byte的倍数分配的内存2.必须在heap的范围之内(即大于heapbase小于heaptop)3.对应的allocbit必须置为1。满足这些条件的对象引用我们称为roots,并且把他们的dosed bit置为1表示不能被GC删除。我想大家已经知道C#中为何连Int和Float都是OBject的原因了吧。在C#中因为都是OBject因此,在tracing的过程中就减少了一次校验。这个减少对性能起到很大的影响。 如果扫描完成,那么Tracing过程便能安全精确的执行。也就是说我们可以在roots中通过reference找到他对应的objects,由于他们是真实的reference,那么我们就能够在compactionphase中移动对应的对象并且修改这些reference。

Trace过程使用了一个可以容纳4k的slots的stack。所有的引用逐个push进入这个堆栈并且同时在markbits中进行标记。当push和mark的工作完成之后,我们开始pop出这些slot并且进行trace。

常规的对象(非数组对象)将通过mptr去访问classblock,classblock将会告诉我们从这个对象中找到的其他对象的reference在那里?当我们在classblock找到一个refernce以后,如果发现他没有被mark,那么我们就在markallocbits中mark他然后把他再压入堆栈。

数组对象利用mptr去访问每个数组元素,如果他们没有mark则mark然后压入堆栈。

Trace过程一直持续进行,直到堆栈为空。

MarkStack OverFlow

由于markStack限制了尺寸,因此它可能会溢出。如果溢出发生,那么我们就设定一个全局的标志来表明发生了MarkStack OverFlow,然后我们将那些不能push入stack的OBject的bit1设定为NotYetScanned。然后当tracing过程完成以后,检验全局标志如果发现有overflow则把NotYetScanned的对象再次压入堆栈开始新的tracing过程。

并行Mark(Parallel Mark)

由于使用逐位清扫(bitwise sweep)和内存紧缩规避功能,GC将化大部分的时间是用于Mark而非前面两项。这就导致了IBM JVM需要开发一个GC的并行版本。并行GC的目的不是以牺牲单CPU系统上的效能来换取在4,8路对称CPU系统上的高效率。

并行Mark的基本思想就是通过多个辅助线程(helper thread)和一个共享工作的工具来减少Marking的时间。在单CPU系统中,执行GC工作的只有一个主线程。Parallel mark仍然需要这个主线程的参与,他充当了管理协调的角色。这个Thread所要执行的工作和单CPU上的一样多,包括他必须扫描C-Stack来鉴别需要收集的roots指针。一个有N路对称CPU的系统自动含有n-1个helper thread并且平均分布在每个CPU上,master thread将scan完的reference集合进行分块,然后交给helper thread独立完成mark工作。

每个Helper thread都被分配了一个独立的本地mark stack,以及一个shareable queue。sharqueue将存放help thread在mark overflow的时候的NotyetScanned对象。然后由master thread将sharequeue中的对象balance到其他已经空闲的thread上去。

并发Mark(Concurrent mark)

Concurrent mark的主要目的在于当heap增长的时候减少GC的pause time。只要heap到达heap limit的时候,Concurrent mark就会被执行。在Concurrent phase中,GC要求应用中的每个线程(不是指helper thread而是应用程序自己开启的线程以便充分利用系统资源)扫描他们自己的堆栈来得到roots。然后使用这些roots来同步的trace 可达对象。Tracing工作是由一个后台的低优先级的线程执行,同时程序自己开启的线程在分配内存的时候必须执行heap lock allocation。

由于使用程序自己开启的线程并发的执行mark live objects,我们必须纪录那些已经trace过的object的变化。这个功能是采用一个叫写闸(write barrier) 来实现的。这个写闸在每次改变引用的时候被激活。它告诉我们什么时候一个对象被跟新过了,以便我们从新扫描那部分heap。写闸的具体实现是Heap会分配出512byte的内存段每个段都分配了一个byte在卡表中(card table)。无论何时一个对象的reference被更新cardtable将同步纪录这个对象的起始地址。使用Byte而不用bit的原因是写byte要比写bit快2倍,而且我们可能希望空余的bit会在未来被用到。

当Concurrent mark执行完毕以后,STW collection(stop total world)将会被执行。stw的意思是指suspend所有程序自己开启的线程。因此我们可以看到如果使用Concurrent mark那

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有