HandleScope是一个栈式的管理方式,每次定义一个HandleScope对象的时候,就会压栈一个结构。接下来定义的Handle类都是在栈顶的那个结构中分配的。然后析构的时候,HandleScope会把管理的内存都释放掉。下面看看定义。
代码语言:javascript复制class HandleScope {
public:
HandleScope() : previous_(current_), is_closed_(false) {
current_.extensions = 0;
}
~HandleScope() {
if (!is_closed_) RestorePreviousState();
}
template <class T> Local<T> Close(Handle<T> value);
static int NumberOfHandles();
static void** CreateHandle(void* value);
private:
HandleScope(const HandleScope&);
void operator=(const HandleScope&);
void* operator new(size_t size);
void operator delete(void*, size_t);
class Data {
public:
// 分配了一块内存后,又额外分配的块数
int extensions;
// 下一个可用的位置
void** next;
// 达到limit执行的地址后说明当前内存块用完了
void** limit;
inline void Initialize() {
extensions = -1;
next = limit = NULL;
}
};
// 当前的HandleScope
static Data current_;
// 上一个HandleScope
const Data previous_;
// HandleScope析构的时候调用
void RestorePreviousState() {
// 不释放第一块内存,如果后面需要内存时这个使用
if (current_.extensions > 0) DeleteExtensions();
// 出栈,指向前面那个
current_ = previous_;
}
bool is_closed_;
void** RawClose(void** value);
// 释放额外申请的内存
static void DeleteExtensions();
friend class ImplementationUtilities;
};
结构图
在这里插入图片描述 HandleScope类没有很多逻辑,他主要是保存前一个scope的信息,然后把current指向自己分配的内存。我们看执行下面的代码的时候是怎样的。
代码语言:javascript复制HandleScope scope;
Handle<String> source = String::New('hello');
我们看下Handle类的定义。
代码语言:javascript复制template<class T>
Handle<T>::Handle(T* obj) {
location_ = reinterpret_cast<T**>(HandleScope::CreateHandle(obj));
}
他传进来一个对象指针,然后调用HandleScope::CreateHandle。我们看看核心代码。
代码语言:javascript复制void** v8::HandleScope::CreateHandle(void* value) {
// 获取下一个可用的地址
void** result = current_.next;
if (result == current_.limit) {
// 申请一块内存,存到一个List里。返回申请到的地址的首地址
result = thread_local.GetSpareOrNewBlock();
thread_local.Blocks()->Add(result);
// 申请了第一块后,又额外申请的块数
current_.extensions ;
// 申请的内存大小,指向尾地址
current_.limit = &result[i::kHandleBlockSize];
}
}
// 下一个可用的地址
current_.next = result 1;
*result = value;
return result;
}
CreateHandle函数的功能是申请一块内存(如果还没有的话),然后next和limit保存这块内存的信息,把传进来的对象指针存到申请到的内存里。
在这里插入图片描述 接着CreateHandle返回保存一个地址(保存了用户定义的对象的地址),赋值给Handle对象的location属性。location对象是T**类型。 我们接着看一下HandleScope析构的时候会怎样。
代码语言:javascript复制 void RestorePreviousState() {
// 不释放第一块内存,如果后面需要内存时这个使用
if (current_.extensions > 0) DeleteExtensions();
// 出栈,指向前面那个
current_ = previous_;
}
首先删除当前HandleScope申请的内存,然后出栈当前的HandleScope。恢复上一个。我们看看DeleteExtensions的核心代码。
代码语言:javascript复制void v8::HandleScope::DeleteExtensions() {
ASSERT(current_.extensions != 0);
thread_local.DeleteExtensions(current_.extensions);
}
void HandleScopeImplementer::DeleteExtensions(int extensions) {
for (int i = extensions; i > 1; --i) {
// 返回删除的元素
void** block = blocks.RemoveLast();
DeleteArray(block);
}
}
block就是图中的List,每个HandleScope记住自己申请的内存块数,然后析构的时候,会释放对应的内存。从而释放堆上的对象。而Handle对象本身是在栈上分配的,也会被析构。如下图。
在这里插入图片描述 这就是v8中的HandleScope的大致原理。