Memory management Javascript中的内存管理

Memory management Javascript中的内存管理,memory-management,garbage-collection,v8,Memory Management,Garbage Collection,V8,看看代码。让我们假设每个语句需要0毫秒才能完成。printAfter2是一个简单的函数,它在调用2秒钟后打印传递给它的字符串 printAfter2 = (obj) => { setTimeout(() => { console.log(JSON.stringify(obj)); }, 2000) } 在下面的代码中,我们创建了一个函数 定义时间为0毫秒的块范围变量obj 以obj(类型为Object)作为参数在0毫秒时调用函数。由于传递的参数

看看代码。让我们假设每个语句需要0毫秒才能完成。printAfter2是一个简单的函数,它在调用2秒钟后打印传递给它的字符串

printAfter2 = (obj) => {
    setTimeout(() => {
        console.log(JSON.stringify(obj));
    }, 2000)
} 
在下面的代码中,我们创建了一个函数

  • 定义时间为0毫秒的块范围变量obj

  • 以obj(类型为Object)作为参数在0毫秒时调用函数。由于传递的参数是对象,因此其引用将传递给函数

  • 然后是console.log函数调用。之后,块在时间0毫秒结束,因此块作用域变量obj也将被销毁

  • 在时间2000时,printAfter2函数获取传递给它的参数值。在这种情况下,它是一个变量的引用,到目前为止应该销毁该变量。但这并没有像预期的那样奏效。它在2000毫秒时打印相同的原始obj,应该在0毫秒时销毁。为什么会这样

我们实际上不需要异步函数,而是忽略它


当变量/参数
obj
超出范围时,这并不意味着任何东西都会立即被销毁。这只意味着对某个对象的一个引用消失,这使得该对象有资格进行垃圾收集,当且仅当该对象是对它的最后一个引用时。垃圾收集器最终(下次运行时)将释放属于不再可访问的对象(即没有对这些对象的引用)的内存。让我们看一个更简单的例子,没有任何闭包:

let o1;
function f1(obj) {
  console.log(obj);  // (3)
}                    // (4)
o1 = new Object();   // (1)
f1(o1);              // (2)
let o2 = o1;         // (5)
o1 = null;           // (6)
// (7)
o2 = new Array();
// (8)
第(1)行显然分配了一个对象,并使用变量
o1
来引用它。注意,对象和变量之间有区别;特别是它们有不同的寿命。 第(2)行将对象传递给函数;当函数执行时(例如在第(3)行),有两个变量引用同一对象:
o1
在外部范围内,以及
f1
的范围内
obj
。 当
f1
在第(4)行终止时,变量
obj
超出范围,但仍可通过
o1
访问对象。 第(5)行创建一个新变量,再次引用同一对象。这在概念上非常类似于将其传递给某个函数。 当
o1
停止引用第(6)行中的对象时,这不会使该对象符合第(7)行中的垃圾收集条件,因为
o2
仍在引用它(“保持它活动”)。只有当
o2
也被重新分配或超出范围时,对象才会变得不可访问:如果垃圾收集器在执行到达第(8)行后的任何时间运行,对象的内存将被释放

(旁注:垃圾收集器实际上并不“收集垃圾”或“销毁对象”,因为它根本不涉及该内存。它只记录存储对象的内存现在可以自由用于新分配的事实。)

在本例中,您正在创建一个闭包
()=>console.log(JSON.stringify(obj))
,其中包含对对象的引用。当这个闭包等待执行时,这个引用将使对象保持活动状态。只有在闭包运行完毕并且自身无法访问之后,才能释放它

以另一种方式说明:

function MakeClosure() {
  let obj = {message: "Hello world"};
  return function() { console.log(JSON.stringify(obj)); };
}

let callback = MakeClosure();
// While the local variable `obj` is inaccessible now, `callback` internally
// has a reference to the object created as `{message: ...}`.
setTimeout(callback, 2000);
// Same situation as above at this point.
callback = null;
// Now the variable `callback` can't be used any more to refer to the closure,
// but the `setTimeout` call added the closure to some internal list, so it's
// not unreachable yet.
// Only once the callback has run and is dropped from the engine-internal list
// of waiting setTimeout-scheduled callbacks, can the `{message: ...}` object get
// cleaned up -- again, this doesn't happen immediately, only whenever the garbage 
// collector decides to run.
function MakeClosure() {
  let obj = {message: "Hello world"};
  return function() { console.log(JSON.stringify(obj)); };
}

let callback = MakeClosure();
// While the local variable `obj` is inaccessible now, `callback` internally
// has a reference to the object created as `{message: ...}`.
setTimeout(callback, 2000);
// Same situation as above at this point.
callback = null;
// Now the variable `callback` can't be used any more to refer to the closure,
// but the `setTimeout` call added the closure to some internal list, so it's
// not unreachable yet.
// Only once the callback has run and is dropped from the engine-internal list
// of waiting setTimeout-scheduled callbacks, can the `{message: ...}` object get
// cleaned up -- again, this doesn't happen immediately, only whenever the garbage 
// collector decides to run.