V8需要声明HandleScope才能清除在范围内创建的任何Local句柄。我知道HandleScope将取消引用这些句柄进行垃圾收集,但我很感兴趣为什么每个Local类都不会像大多数内部ref_ptr类型的助手那样自行解除引用。
我的想法是,HandleScope可以通过一次性转储大量句柄而不是像在ref_ptr类型作用域类中那样逐个转储来更有效地完成它。
答案 0 :(得分:6)
以下是我理解the documentation和handles-inl.h
源代码的方法。我也可能完全错了,因为我不是V8开发人员,文档很少。
垃圾收集器有时会将内容从一个内存位置移动到另一个内存位置,并且在一次扫描期间,还会检查哪些对象仍然可以访问,哪些不可访问。与像std::shared_ptr
这样的引用计数类型相比,它能够检测和收集循环数据结构。为了实现这一切,V8必须对可以访问的对象有一个很好的了解。
另一方面,在某些计算的内部,对象被创建和删除了很多。对于每个此类操作,您不需要太多开销。实现这一目标的方法是创建一堆句柄。在某些C ++计算中,该堆栈中列出的每个对象都可以从某个句柄中获得。除此之外,还有持久句柄,可能需要更多的工作来设置,并且可以在C ++计算之外生存。
拥有一堆引用需要您以类似堆栈的方式使用它。该堆栈中没有“无效”标记。堆栈底部到顶部的所有对象都是有效的对象引用。确保这一点的方法是LocalScope
。它使事物层次化。使用引用计数指针,您可以执行以下操作:
shared_ptr<Object>* f() {
shared_ptr<Object> a(new Object(1));
shared_ptr<Object>* b = new shared_ptr<Object>(new Object(2));
return b;
}
void g() {
shared_ptr<Object> c = *f();
}
首先创建对象1,然后创建对象2 然后,然后函数返回并且对象1被销毁,然后对象2被销毁。这里的关键点是对象1无效但对象2仍然有效的时间点。这是LocalScope
旨在避免的内容。
其他一些GC实现检查C堆栈并查找它们在那里找到的指针。这很容易出现误报,因为实际上数据的东西可能被误解为指针。对于可达性,这可能看起来相当无害,但是当你重新移动对象时重写指针,这可能是致命的。它还有许多其他缺点,并且很大程度上依赖于语言的低级实现如何实际工作。 V8通过将句柄堆栈与函数调用堆栈分开来避免这种情况,同时确保它们充分对齐以保证所提到的层次结构要求。
提供另一个比较:只有一个shared_ptr
引用的对象在其C ++块作用域结束后变为可收集(实际上将被收集)。当离开包含v8::Handle
对象的最近的封闭范围时,HandleScope
引用的对象将变为可收集对象。因此,程序员可以更好地控制堆栈操作的粒度。在性能很重要的紧密循环中,为整个计算维护一个HandleScope
可能很有用,这样您就不必经常访问句柄堆栈数据结构。另一方面,这样做会在计算的整个持续时间内保持所有对象,如果这是一个迭代多个值的循环,那将非常糟糕,因为所有这些都将保持到最后。但是程序员可以完全控制,并且可以以最恰当的方式安排事情。
就个人而言,我确保构建HandleScope
一般情况下,如果我可以确定调用此函数的其他所有函数都已设置HandleScope
,则不会为每个内部函数创建HandleScope
。但那可能是一种品味问题。
答案 1 :(得分:3)
免责声明:这可能不是官方的答案,更多的是我的关键;但v8文档很难 对此主题有用。所以我可能被证明是错的。
从我的理解,开发各种基于v8的支持应用程序。它是处理C ++和javaScript环境之间差异的一种方法。
想象一下以下序列,自解除引用指针可能会破坏系统。
- JavaScript调用C ++包装的v8函数:让我们说helloWorld()
- C ++函数创建一个值为“hello world = x”
的v8 ::句柄- C ++将值返回给v8虚拟机
- C ++函数通常会清理资源,包括解除引用句柄
- 另一个C ++函数/进程,覆盖释放的内存空间
- V8读取句柄:数据不再相同“地狱!@(#...”
醇>
这只是两者之间复杂不一致的表面;因此,为了解决将 JavaScript VM(虚拟机)连接到 C ++接口代码的各种问题,我相信开发团队决定通过以下方式简化问题。 ..
- 所有变量句柄,存储在“buckets”又名HandleScopes 中,构建/编译/运行/销毁 相关的 C ++代码。
- 另外所有函数句柄,仅引用C ++静态函数(我知道这很烦人),这确保了“存在” 无论构造函数/析构函数如何,函数调用。
从开发的角度考虑,它标志着JavaScript VM开发团队和C ++集成团队(Chrome开发团队?)之间的非常强烈的区别。允许双方工作而不互相干扰。
最后,为了简单起见,也可以模拟多个虚拟机:因为v8最初是用于谷歌浏览器。因此,每当我们打开/关闭选项卡时,只需创建和销毁一个简单的HandleScope,更容易进行GC管理,尤其是在运行许多VM的情况下(Chrome中的每个选项卡)。