作为 ECMAScriptv5,每次控制输入代码时,enginge 都会为函数代码<>LexicalEnvironment(LE) 和一个VariableEnvironment(VE)/strong>,这两个对象是调用 NewDeclarativeEnvironment(ECMAScript v5 10.4.3) 的结果完全相同的引用,函数代码中声明的所有变量都存储在环境记录 componentof VariableEnvironment( ECMAScript v5 10.5 ),这是闭包的基本概念。
令我困惑的是Garbage Collect如何使用这种闭包方法,假设我有这样的代码: 在 据我所知,如果 javascript 引擎使用引用计数方法 进行垃圾回收,则对象 有人可能会说引擎知道 f2 的 VariableEnvironment 不使用 f1 的 VariableEnvironment,所以整个 f1 的 VariableEnvironment 都会被 GC,所以还有另一个代码片段可能会导致更复杂的情况: 在这种情况下, 所以我想问一下,现代 javascript 引擎(JScript.dll/V8/SpiderMonkey ...)如何处理这种情况,是否有标准指定规则或它是否基于实现,以及 javascript 引擎处理此类的确切步骤是什么执行垃圾收集时的对象图。 谢谢。function f1() {
var o = LargeObject.fromSize('10MB');
return function() {
// here never uses o
return 'Hello world';
}
}
var f2 = f1();
var f2 = f1() 行之后,我们的对象图将是:global -> f2 -> f2's VariableEnvironment -> f1's VariableEnvironment -> o
o 至少有 1 个引用 并且永远不会被 GC。显然这会导致内存浪费,因为 o 永远不会被使用,但总是存储在内存中。function f1() {
var o1 = LargeObject.fromSize('10MB');
var o2 = LargeObject.fromSize('10MB');
return function() {
alert(o1);
}
}
var f2 = f1();
f2 使用存储在f1 的 VariableEnvironment 中的 o1 对象,因此 f2 的 VariableEnvironment 必须保持对f1的VariableEnvironment的引用,这导致o2也不能被GC,进一步造成内存浪费。
最佳答案
tl;dr 回答: "Only variables referenced from inner fns are heap allocated in V8. If you use eval then all vars assumed referenced." .在您的第二个示例中,o2 可以在堆栈上分配并在 f1 退出后被丢弃。
我认为他们无法应对。至少我们知道有些引擎不能,因为这是许多内存泄漏的原因,例如:
function outer(node) {
node.onclick = function inner() {
// some code not referencing "node"
};
}
其中 inner 关闭 node,形成一个循环引用 inner -> outer 的 VariableContext -> node -> inner,永远不会例如在 IE6 中释放,即使 DOM 节点已从文档中删除。不过有些浏览器处理得很好:循环引用本身不是问题,问题是 IE6 中的 GC 实现。但现在我离题了。
打破循环引用的一种常见方法是在 outer 的末尾清空所有不必要的变量。即,设置 node = null。那么问题是现代 javascript 引擎是否可以为你做这件事,它们能以某种方式推断出变量没有在 inner 中使用吗?
我认为答案是否定的,但事实证明我是错的。原因是下面的代码执行得很好:
function get_inner_function() {
var x = "very big object";
var y = "another big object";
return function inner(varName) {
alert(eval(varName));
};
}
func = get_inner_function();
func("x");
func("y");
使用 this jsfiddle example 亲自查看. inner 中没有对 x 或 y 的引用,但仍然可以使用 eval 访问它们。 (令人惊讶的是,如果您将 eval 别名为其他东西,比如 myeval,然后调用 myeval,您不会获得新的执行上下文 - 这是即使在规范中,也请参阅 ECMA-262 中的第 10.4.2 节和第 15.1.2.1.1 节。)
编辑:根据您的评论,一些现代引擎似乎确实做了一些聪明的把戏,所以我试着多挖掘一点。我遇到了这个 forum thread讨论这个问题,特别是指向 a tweet about how variables are allocated in V8 的链接.它还专门涉及 eval 问题。看起来它必须解析所有内部函数中的代码。并查看引用了哪些变量,或者是否使用了eval,然后确定每个变量应该分配在堆上还是堆栈上。挺整洁的。这是 another blog其中包含许多关于 ECMAScript 实现的细节。
这意味着即使内部函数永远不会“逃脱”调用,它仍然可以强制在堆上分配变量。例如:
function init(node) {
var someLargeVariable = "...";
function drawSomeWidget(x, y) {
library.draw(x, y, someLargeVariable);
}
drawSomeWidget(1, 1);
drawSomeWidget(101, 1);
return function () {
alert("hi!");
};
}
现在,由于 init 已完成其调用,因此不再引用 someLargeVariable 并且应该符合删除条件,但我怀疑它不是,除非内部函数drawSomeWidget 已被优化(内联?)。如果是这样,当使用自执行函数模拟具有私有(private)/公共(public)方法的类时,这可能会经常发生。
在下面回答雷诺斯的评论。我在调试器中尝试了上述场景(稍作修改),结果如我所料,至少在 Chrome 中是这样:
执行内部函数时,someLargeVariable 仍在范围内。
如果我在内部 drawSomeWidget 方法中注释掉对 someLargeVariable 的引用,那么您会得到不同的结果:
现在 someLargeVariable 不在范围内,因为它可以在堆栈上分配。
关于javascript - 关于闭包、LexicalEnvironment 和 GC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8665781/
我是Ruby的新手,有些闭包逻辑让我感到困惑。考虑这段代码:array=[]foriin(1..5)array[5,5,5,5,5]这对我来说很有意义,因为i被绑定(bind)在循环之外,所以每次循环都会捕获相同的变量。使用每个block可以解决这个问题对我来说也很有意义:array=[](1..5).each{|i|array[1,2,3,4,5]...因为现在每次通过时都单独声明i。但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?array=[]foriin1..5j=iarray[5,5,5,5,5]因为j每次循环都是新的,我认为每次循环都会捕获不同的变量。例如,这绝对
我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的
我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?
我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan
我在Ruby中遇到了一个关于Dir[]和File.join()的简单程序,blobs_dir='/path/to/dir'Dir[File.join(blobs_dir,"**","*")].eachdo|file|FileUtils.rm_rf(file)ifFile.symlink?(file)我有两个困惑:首先,File.join(@blobs_dir,"**","*")中的第二个和第三个参数是什么意思?其次,Dir[]在Ruby中有什么用?我只知道它等价于Dir.glob(),但是,我对Dir.glob()确实不是很清楚。 最佳答案
1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>
目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'
我看到有关未找到文件min.map的错误消息:GETjQuery'sjquery-1.10.2.min.mapistriggeringa404(NotFound)截图这是从哪里来的? 最佳答案 如果ChromeDevTools报告.map文件的404(可能是jquery-1.10.2.min.map、jquery.min.map或jquery-2.0.3.min.map,但任何事情都可能发生)首先要知道的是,这仅在使用DevTools时才会请求。您的用户不会遇到此404。现在您可以修复此问题或禁用sourcemap功能。修复:获取文
是否存在GC.disable会降低性能的情况?只要我使用的是真正的RAM而不是交换内存,就可以这样做吗?我正在使用MRIRuby2.0,据我所知,它是64位的,并且使用的是64位的Ubuntu:ruby2.0.0p0(2013-02-24revision39474)[x86_64-linux]Linux[redacted]3.2.0-43-generic#68-UbuntuSMPWedMay1503:33:33UTC2013x86_64x86_64x86_64GNU/Linux 最佳答案 GC.disable将禁用垃圾回收。像rub