JavaScript WeakMap продолжает ссылаться на gc'ed объекты

Я испытываю слабые карты JavaScript, после того, как я попробовал этот код в консоли разработчика Google Chrome, запустив с параметром --js-flags="- expose-gc", я не понимаю, почему у карты слабых карт есть ссылка на ab, если a gc'ed.

var a = {listener: function(){ console.log('A') }}
a.b = {listener: function(){ console.log('B') }}

var map = new WeakMap()

map.set(a.b, [])
map.set(a, [a.b.listener])

console.log(map) // has both a and a.b

gc()
console.log(map) // still have both a and a.b

a = undefined
gc()
console.log(map) // only have a.b: why does still have a reference to a.b? Should'nt be erased?

1 ответ

Решение

В вашем примере кода вы не выпускаете a переменная. Это var верхнего уровня, который никогда не выходит из области видимости и никогда не получает явной разыменования, поэтому он остается в WeakMap. WeakMap/WeakSet освобождает объекты, если в вашем коде больше нет ссылок на них. В вашем примере, если вы console.log(a) после одного из ваших gc() звонки, вы все равно ожидаете a быть живым, верно?

Итак, вот рабочий пример, показывающий WeakSet в действии и как он удалит запись, когда все ссылки на нее исчезнут: https://embed.plnkr.co/cDqi5lFDEbvmjl5S19Wr/

const wset = new WeakSet();

// top level static var, should show up in `console.log(wset)` after a run
let arr = [1];
wset.add(arr);

function test() {
  let obj = {a:1}; //stack var, should get GCed
  wset.add(obj);
}

test();

//if we wanted to get rid of `arr` in `wset`, we could explicitly de-reference it
//arr = null;

// when run with devtools console open, `wset` always holds onto `obj`
// when devtools are closed and then opened after, `wset` has the `arr` entry,
// but not the `obj` entry, as expected
console.log(wset);

Обратите внимание, что открытые инструменты разработчика Chrome не позволяют собирать мусор некоторым объектам, что затрудняет просмотр этого в действии.

Другие вопросы по тегам