V8需要声明一个HandleScope,以便清除在作用域中创建的任何本地句柄。我理解HandleScope将取消这些句柄的垃圾收集,但我感兴趣的是为什么每个Local不像大多数内部ref_ptr类型帮助程序那样自行解除引用。
我的想法是,HandleScope可以通过一次性转储大量句柄来提高效率,而不是像在ref_ptr类型作用域类中那样一个接一个地转储句柄。
发布于 2015-04-07 15:30:10
下面是我对文献资料和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。但这可能是品味的问题。
发布于 2012-04-24 04:34:48
免责声明:这可能不是一个正式的答案,更多的是我自己的问题;但是v8文档在这个主题上几乎没有用。所以我可能被证明是错的。
据我所知,在开发各种基于v8的后台应用程序时。它是处理C++和javaScript环境之间差异的一种方法。
想象一下下面的顺序,自解除引用指针可以破坏系统.
这只是与之间复杂不一致的表面;因此,为了解决将JavaScript VM (虚拟机)连接到C++接口代码的各种问题,我相信开发团队决定通过以下方式简化这个问题.
从开发的角度来考虑这个问题,在中,它标志着JavaScript VM开发团队和C++集成团队(Chrome?)之间有很大的区别。允许双方在不相互干扰的情况下开展工作。
最后,为了简单起见,还可以模仿多个VM :因为v8最初是为google设计的。因此,每当我们打开/关闭选项卡时,就会创建和销毁简单的HandleScope,这使得GC管理更加容易,特别是在运行了许多VM的情况下(每个选项卡都在chrome中)。
https://stackoverflow.com/questions/9510822
复制相似问题