在kvm内部中在分配内饰时使用了free chunk list.其定义如下:
struct chunkStruct {
long size; /* 当前chunk的大小,不包含该字段 */
CHUNK next; /* 指向下一个chunk */
};
如图所示:
这里需要注意的是:
-
size使用与常规对象头相同的格式存储,但是只使用最高的24位(见上文)。6个低位必须全部为零,字才能被识别为chunk头。
-
size不包括大小字段(headersize)本身,即,如果chunk的物理大小为3个字,则size的值为2
-
Chunk总是至少2个字(64位)长,因为这是分配新对象所需的最小大小(需要保存size和next字段)。小于此值的可用内存区域将自动与其他对象合并(从而为对象添加内碎片)。实际上,这种情况很少发生。
该结构是一个链表,如图:
分配chunk
分配chunk的方法为allocateFreeChunk.其代码如下:
static cell* allocateFreeChunk(long size)
{
CHUNK thisChunk = FirstFreeChunk;
CHUNK* nextChunkPtr = &FirstFreeChunk;
cell* dataArea = NIL;
for (thisChunk = FirstFreeChunk, nextChunkPtr = &FirstFreeChunk;
thisChunk != NULL;
nextChunkPtr = &thisChunk->next, thisChunk = thisChunk->next) {
/* Calculate how much bigger or smaller the */
/* chunk is than the requested size 进行size的比较*/
long overhead = SIZE(thisChunk->size) + HEADERSIZE - size; // SIZE(thisChunk->size) + HEADERSIZE 当前FirstFreeChunk的大小
// overhead = 当前FirstFreeChunk 与 size(请求分配空间大小) 的差额.
// 如果剩余空间大与1的话,则直接使用Chunk,大于1的目的是还需要分配对象头
if (overhead > HEADERSIZE) {
// SIZE(thisChunk->size) + HEADERSIZE - size - HEADERSIZE = SIZE(thisChunk->size) - size
thisChunk->size = (overhead - HEADERSIZE) << TYPEBITS;
// 进行分配
dataArea = (cell *)thisChunk + overhead;
// 保存大小,不含对象头
*dataArea = (size - HEADERSIZE) << TYPEBITS;
return dataArea;
} else if (overhead >= 0) {
/*
* 将整个Chunk 进行分配,如果剩余空间是在 [0,1] 之间
*/
*nextChunkPtr = thisChunk->next;
dataArea = (cell *)thisChunk;
/* Store the size of the object in the object header 保存大小 */
// size + overhead - HEADERSIZE = size + SIZE(thisChunk->size) + HEADERSIZE - size -HEADERSIZE = SIZE(thisChunk->size)
*dataArea = (size + overhead - HEADERSIZE) << TYPEBITS; // 此时保存的大小就是当前Chunk的大小.
return dataArea;
}
}
/* If we got here, there was no chunk with enough memory available 如果到了这里,则意味着没有适会的chunk*/
return NULL;
}
这里分三种情况:
- chunk 富足,满足size,且又剩余.此时分配前后的情况如图:
-
chunk 刚好等于size.此时会将chunk 从free chunk list中移除.移除代码为:
*nextChunkPtr = thisChunk->next;
此时的情况如图:
-
chunk 与size间的剩余为1个cell,则此时会将该chunk 全部进行分配,但是会形成内碎片.此时的情况和第2种类似.只不过大小比size大了1.这里就不贴了
接下来我们会开始讲述kvm中的垃圾收集的实现.