js引擎v8源码分析之HandleScope(基于v8 0.1.5)

HandleScope是一个栈式的管理方式,每次定义一个HandleScope对象的时候,就会压栈一个结构。接下来定义的Handle类都是在栈顶的那个结构中分配的。然后析构的时候,HandleScope会把管理的内存都释放掉。下面看看定义。

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指向自己分配的内存。我们看执行下面的代码的时候是怎样的。

HandleScope scope;
Handle<String> source = String::New('hello');

我们看下Handle类的定义。

template<class T>
Handle<T>::Handle(T* obj) {
  location_ = reinterpret_cast<T**>(HandleScope::CreateHandle(obj));
}

他传进来一个对象指针,然后调用HandleScope::CreateHandle。我们看看核心代码。

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析构的时候会怎样。

  void RestorePreviousState() {
    // 不释放第一块内存,如果后面需要内存时这个使用
    if (current_.extensions > 0) DeleteExtensions();
    // 出栈,指向前面那个
    current_ = previous_;
   }

首先删除当前HandleScope申请的内存,然后出栈当前的HandleScope。恢复上一个。我们看看DeleteExtensions的核心代码。

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的大致原理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值