Chrome/V8 не мусор собирает круговую ссылку?

Взгляните на эту часть снимка Chrome heaphot:

Круговая ссылка Chrome

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

"Самый короткий" путь к корню - это, в конце концов, циклический путь (он никогда не достигает корня). Что заставляет задуматься, как средство просмотра снимков даже может назначить ему расстояние до 12? Это просто количество шагов, которые потребовались в цикле, прежде чем сдаться? Обратите внимание, как расстояние никогда не становится ниже 11.

Я читал, что для очистки подграфов с циклическими ссылками может потребоваться несколько итераций. Но повторные принудительные коллекции (с кнопкой корзины на вкладке Timeline) не смогли очистить эти объекты.

Обратите внимание, что поиск по ссылкам "185" в конечном итоге приводит к тому же system / Context @862399, поэтому на самом деле нет пути от корня к этому объекту (по крайней мере, здесь не видно).

Я схожу с ума, или сборщик мусора действительно сломался? Я не помню, чтобы эта проблема была в прошлом. Я нахожусь в Chrome 45.0.2454.101. Бета 46.0.2490.64 ведет себя одинаково.

Ответы

Ответ 1

Чтобы быть абсолютно честным, нам нужно быстро взглянуть на тестовый код some, где вы воспроизвели это, но у меня есть общее представление о том, что вы испытываете. Если я ошибаюсь, и вы можете предоставить некоторый тестовый код, подтверждающий это, сообщите мне.

Как вы, кажется, уже знаете, чтобы "очистить", Javascript больше не хочет ссылаться на элемент, который хочет освободиться.

Простой пример:

// Currently not eligible for garbage
var myObj = {
    data : 'test'
};

// Reference data inside myObj
// A unique identifier to myObj.data now exists 
var myData = myObj.data;

// Whoops
myObj = 'something else';

// Because myData exists, so does data and can not be freed either, understandable
// This sounds simple and logical but most do not understand what is happening in the engine
// A relationship has been born between 'myData' and 'data' and as long as it exists, it is not eligible for garbage and remains in memory
console.log( myData );

Ваш код, вероятно, более сложный, чем это, но это может помочь объяснить, как где-то мусор не может быть собран, поскольку цепочка областей видимости может быть использована для ссылки.

Рассмотрим следующее

function oops(text){

    function doStuff(){
        return text.toLowerCase();
    }
    return doStuff();
}

// 'doStuff' stays alive thanks to 'test' below.
var test = oops('closure');

функция doStuff не будет собираться мусором, поскольку на нее ссылаются test.

// You can see where this is headed. We have 2 references to the same 'doStuff' function object with separate unique identifiers now below.
var test2 = oops('closures...');

// This is now another unique identifier to 'doStuff'
var test3 = test2;

// doStuff survives yet still
test = 0;
test2 = 0;

// Now we let the function object of 'doStuff' be freed because there is no longer any references to it
test3 = 0;

Это по существу утечка памяти, которую мы создали. Каждый раз, когда вы вызываете oops, вы создаете объект функции doStuff с уникальным идентификатором.

Способ избежать этого может быть

function doStuff( text ){
    return text.toLowerCase();
}

function oops( text ){
    return doStuff();
}

var test = oops( 'closure' );

Теперь у нас нет утечек памяти. doStuff вызывается, а не создан.

Присмотритесь к своему коду, и вы обнаружите, что вы, вероятно, делаете это где-то.

Если вы возитесь с элементами, и я думаю, что вы могли бы быть, IBM имеет хорошую статью о круговых ссылках, вы можете взглянуть в.


Поздно, и некоторые из них были непроверены, но теория все еще существует, поэтому, если я что-то напутал и т.д., дайте мне знать, и я могу завтра взглянуть на будущих посетителей этой страницы.