Почему использование global.gc () перед созданием объекта предотвращает отрицательную дельту в использовании кучи?

1

У меня есть этот код, предназначенный для запуска в дочернем процессе (через fork, если быть конкретным), чтобы попытаться измерить размер объекта в памяти:

const syncComputationThatResultsInALargeObject = require('whatever');

let initMemory;
let finalMemory;
let obj;
process.on('message', () => {
  // global.gc();
  initMemory = process.memoryUsage().heapUsed;
  obj = syncComputationThatResultsInALargeObject();
  finalMemory = process.memoryUsage().heapUsed;

  process.send({
      memoryCost: finalMemory - initMemory,
  });
});

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

Я удивляюсь, что иногда возвращаемый memoryCost отрицательный, подразумевая, что размер кучи меньше после создания obj.

Если я однако разрешаю ручные вызовы GC с использованием --expose-gc в узле и вызывать GC перед опросом использования кучи, перед созданием объекта я никогда не получаю отрицательные значения.

Может ли кто-нибудь дать ответ, почему это может произойти? Я использую узел 6.14.4 на Ubuntu 18.04.1, ядро 4.15.0-30-generic. Благодарю.

EDIT: Это происходит, даже если я finalMemory на obj после назначения finalMemory, например, помещая ссылку на одно из своих полей в объекте, переданном process.send.

  • 1
    это просто предположение, но не удивительно, если syncComputationThatResultsInALargeObject просто повторно использует мусорную память, которая еще не была собрана, но, конечно, после вызова gc такой памяти нет
  • 1
    Умный компилятор может заметить, что obj нигде не доступен, и собрать мусор даже до вычисления finalMemory
Теги:
garbage-collection
child-process

1 ответ

0
Лучший ответ

После нескольких тестов я смог понять, почему это происходит.

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

То, что я обнаружил, заключается в том, что при повторном вычислении несколько раз для разных наборов параметров, это то, что наборы параметров, которые генерируют более крупный объект, имеют гораздо большую дисперсию между результатами, даже когда я вызываю global.gc() в указанной строке,

Таким образом, я приписываю наблюдаемое поведение тому, что иногда ГК вызывается внутри вычислительной функции неуправляемым образом. Большие размеры объектов означают большее использование памяти, что означает более частые (возможно, непредсказуемые) вызовы GC, что означает большую дисперсию результатов для равных параметров.

  • 0
    Вы можете написать const array = [] затем syncComputationThatResultsInALargeObject push- syncComputationThatResultsInALargeObject в массив, а затем очистить массив после того, как закончите измерение кучи. Сохранит ли это память, чтобы вычисления имели смысл?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню