麻痹的不会在优快云上贴图片,只好用文字来表达了
实际上,这个最简单的垃圾回收器的实现,我们只用关心,两个指针,以及一个结构,在我的代码中如下
// 定义只在本文件中使用的静态变量,并初始化
static BYTE* m_begin = (BYTE*)HeaderSize;
static BYTE* m_end = (BYTE*)HeaderSize;
// 定义存储数据的数据结构
typedef struct MemBlock _MemBlock;
struct MemBlock
...{
_MemBlock* pPrev;
char buffer[BlockSize];
};以及,为什么只有2个指针以及这一个结构,就可以完成GC的基本功能
一、初始化
由两个指针的初始化我们可以看出
// 定义一些只在本文件中使用的宏
#define HeaderSize (sizeof(void*))如果在32位的环境中 两个值都是4,为什么这样?先不管他,从这里我们至少可以看出一个情况
m_end-m_begin == 0 ,也就是说 最开始的时候,用户这时候可使用的内存为0
可以先记住 m_end-m_begin 指的是GC内部这时候可交给用户使用的内存大小!
二、GC内存的申请
当用户第一调用 gc_malloc 函数时,那么一定要进行新的内存的申请
这时候应该申请多大呢?
这要看 BlockSize 的大小,当用户申请的内存大于我们定义的块大小时,那么为了能给用户一块连续的
内存,GC将按照用户的需要,重新申请足够的内存
// 这里根据用户用户请求的内存块的大小
// 来判断是使用默认块大小还是开辟足够的内存
if(cb >= BlockSize) 
...{
pNewMemBlock = (_MemBlock*)malloc(HeaderSize + cb);
}
else
...{
// 这里开辟的内存的大小为_MemBlock
// 即 sizeof(_MemBlock *) + BlockSize
// 也等于 HeaderSize + BlockSize
// 则下面开辟内存也可以换成这句
// _MemBlock* pNew = (_MemBlock*)malloc(HeaderSize + BlockSize);
pNewMemBlock = (_MemBlock*)malloc(sizeof(_MemBlock));
}之后,如果下一次用户申请内存时,GC内部有足够的内存给用户的话,将不再进行内存的申请,只需要移动m_end指针即可。
三、两个指针在做什么
// 重新设置m_begin指针,将 m_begin 指向新内存块的开始
m_begin = pNewMemBlock->buffer;
第一次时,m_begin指向的是用户可用内存块的最开始的位置
之后呢?哈哈,其实之后也是这样,m_begin永远指向用户可使用的内存块的最开始的位置,并且m_begin-HeaderSize 这个地址(指针),指向了这个块(_MemBlock)这个数据结构的最开始的位置,也就是说我们可以通过m_begin得到每次申请的内存块的指针,也就是说 m_begin永远指向GC内部最后申请的内存块。
m_end
当GC内部不需要进行内存申请时,他始终在现有的内存块中进行移动,当GC内部进行内存申请时,m_end指向新内存块的尾部。并且无论GC内部申请了还是没申请内存,m_end始终指向一个内存地址,这个内存地址有足够的内存可以交给用户使用。
// 将 m_end 指向新内存块的结尾处
if(cb >= BlockSize)
m_end = pNewMemBlock->buffer + cb;
else
m_end = pNewMemBlock->buffer + BlockSize;
// 将 m_end 从后向前移动 cb 个字节
// 并将这一段内存交给用户使用
m_end -= cb;
return m_end;
四、两个指针怎么就能实现,所有的内存块的管理呢?
实际上这里使用的存储结构跟链表有点相似,但并不是典型的链表
// 定义存储数据的数据结构
typedef struct MemBlock _MemBlock;
typedef struct MemBlock
...{
_MemBlock* pPrev;
char buffer[BlockSize];
};
这个数据结构中 pPrev 的值的改变,是在下一次,GC内部进行内存申请时才被改变的
// 将新内存块的链指针指向之前的内存块
pNewMemBlock->pPrev = pNowHeader;
// 重新设置m_begin指针,将 m_begin 指向新内存块的开始
m_begin = pNewMemBlock->buffer;
总结:
用户在使用这个GC时,实际上始终在跟m_end打交道,m_end这个指针,提供给用户内存的访问能力
m_begin 这个指针 指向正在使用的内存快数据结构中 buffer 最开始
这个GC使用的数据结构是一个类似链表的数据结构,但对这个链表的操作,却比链表更简单。
本文介绍了一个简单的垃圾回收器的设计原理。通过两个指针及一个内存块结构,实现了内存分配和管理的基础功能。理解其工作流程有助于深入学习内存管理机制。
1480

被折叠的 条评论
为什么被折叠?



