У меня есть этот код, предназначенный для запуска в дочернем процессе (через 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
.
После нескольких тестов я смог понять, почему это происходит.
В моем конкретном примере функции вычисления я могу передать несколько параметров, которые влияют на результирующий размер объекта.
То, что я обнаружил, заключается в том, что при повторном вычислении несколько раз для разных наборов параметров, это то, что наборы параметров, которые генерируют более крупный объект, имеют гораздо большую дисперсию между результатами, даже когда я вызываю global.gc()
в указанной строке,
Таким образом, я приписываю наблюдаемое поведение тому, что иногда ГК вызывается внутри вычислительной функции неуправляемым образом. Большие размеры объектов означают большее использование памяти, что означает более частые (возможно, непредсказуемые) вызовы GC, что означает большую дисперсию результатов для равных параметров.
const array = []
затем syncComputationThatResultsInALargeObject
push- syncComputationThatResultsInALargeObject
в массив, а затем очистить массив после того, как закончите измерение кучи. Сохранит ли это память, чтобы вычисления имели смысл?
obj
нигде не доступен, и собрать мусор даже до вычисленияfinalMemory