关闭未使用变量的内存泄漏 [英] Closure memory leak of unused variables

查看:29
本文介绍了关闭未使用变量的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解在什么情况下不再使用的变量存储在闭包中并导致内存泄漏.我最喜欢的结果是没有",但事实并非如此.

据我了解,一旦在另一个函数中声明一个函数,便为其内部[[scope]]分配其封装函数的LexicalEnvironment.此时,此LexicalEnvironment具有引用局部变量和整个作用域链.这基本上包括该函数可以访问的所有个自由变量(据我了解的

任何未保存在闭包中的数据都将变成垃圾并可以收集,因此不会泄漏.

I'd like to understand under which circumstances variables which are no further used are stored in closures and lead to memory leaks. My most preferred outcome would be "there are none", but this doesn't seem to be the case.

From what I understand, once a function is declared inside another function, its internal [[scope]] is assigned the LexicalEnvironment of its encapsulating function. This LexicalEnvironment has reference local variables and the entire scope chain at that point. This basically includes all free variables the function could access (from what I understood of lostechies, javascript closures explained).

Here the first issue arises: this should mean all those variables can be reached as long as the function lives. E.g. the following should already leak:

function a() {
    let big = new Array(1000000).join('*'); //never accessed
    //function unused() { big; }
    return () => void 0;
}
 
let fstore = [];
function doesThisLeak() {
  for(let i = 0; i < 100; i++) fstore.push(a());
}

doesThisLeak();

This luckily doesn't seem to be the case on my firefox. I've received several explanations to why this doesn't leak, from "the jitter is smart" to "LexicalEnvironment is a record type which means GC can collect the unused variables". I still don't know whether either is correct, whether this doesn't leak on all modern runtimes and why.

After further research, I found auth0, four types of leaks in javascript (sadly, there appears to be no html id to jump to, the relevant part is "4: Closures") which shows a way to trick whatever smart thing is collecting the unused variables. In above snippet, when just uncommenting the "unused" function, I do not see RAM usage ever going down again (it was already noted that it could be GC simply did not run for other reasons. However, so far, I am assuming it leaks. I also got told this was limited to firefox, but it appeared to produce similar behavior in chrome)

This example (in case it really does what i believe it does), shows that completely unused variables can leak due to a function declaration in the same scope.

To conclude my problems:

  1. What is the reason for, in the above snippet, "big" getting collected (when "unused" is commented) and does this happen on all modern runtimes?
  2. Assuming the example with the "unused" function not commented leaks, what are best practices to avoid such accidental leaks? Are there any more? I already got the suggestion of null'ing all local variables which are not further used at the end of functions, however, this seems absurdly ugly. I fear using temporary variables for pre-calculations and accidentally leaking.

PS: It is quite hard to make certain that this question has not already been asked in the jungle of questions about memory leaks with closures.

解决方案

The compiler can examine the code of the returned function to see which free variables it references, and only those variables need to be saved in the closure, not the entire LexicalEnvironment. You can see this by examining the closure in the Javascript debugger.

function a() {
  let big = new Array(1000000).join('*');
  let small = "abc"; // is accessed
  return (x) => small + x;
}

fun = a();
console.dir(fun);

function b() {
    let big = "pretend this is a really long string";
    function unused() { big; }
    return () => void 0;
}

fun = b();
console.dir(fun);

When you expand the first function in the debugger, you'll see small in the Closure property, but not big. Unfortunately, the Chrome compiler doesn't seem to be clever enough to detect when the variable is referenced in an unused function that isn't returned, so it doesn't need to be saved, so we get a leak in b().

Any data that isn't saved in the closure becomes garbage and can be collected, so it won't leak.

这篇关于关闭未使用变量的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆