Как работает сборщик мусора Node.js(v8)?
Я провел несколько тестов с моим приложением node.js, который искал утечку памяти, которую должен выполнять мой код. Я запускаю script, который, на мой взгляд, должен утечка памяти, но я удивлен результатом.
redisClient.on('message', initRequest);
function onSuccess(self, json){
console.dir(json);
}
function initRequest(channel, message){
var request = new RequestObject({
redisMessage: message
});
request.on('success', onSuccess);
}
redisClient испускает пару событий сообщения в секунду. Это означает, что функция initRequest
вызывается довольно часто. Каждый раз, когда объект request
создается в памяти, а функция onSuccess
привязывается к событию "success".
Я предположил (но здесь я могу ошибаться), что, поскольку в этом случае есть слушатель (onSuccess
), привязка к этому объекту не может быть собрана мусором. Тогда я подумал, что использование памяти будет расти, поскольку память не будет бесплатной.
В качестве решения этой потенциальной утечки я хотел использовать .once
вместо .on
, так как это приведет к отключению слушателя, и объект может быть собран в мусор.
Я использовал pmap для тестирования обоих сценариев (сравнение .on
и .once
и другого сценария, о котором здесь не стоит упоминать), и я не нашел большой разницы.
![enter image description here]()
Подводя итог, у меня есть 2 вопроса:
-
Является ли это обычным поведением GC для очистки памяти через определенные промежутки времени или после того, как он достигнет некоторого threashold вместо непрерывной очистки?
-
Я правильно предполагаю, что код примера с .on
должен протекать в памяти, которую я не вижу на графике потребления памяти?
Ответы
Ответ 1
1: да: -)
2: В общем случае утечка памяти при использовании прослушивателей событий заключается в том, что объект, который прослушивается, не может быть собран из мусора, потому что объект, который испускает, сохраняет ссылку на него.
Итак, в вашем коде функция onSuccess
будет ссылаться на ваш объект request
. Однако, onSuccess
- это только одна функция, которая повторно используется как слушатель для всех объектов запроса, поэтому это не должно приводить к накоплению памяти.
Sidenote: я не знаю внутренности redisClient
и RequestObject
, но для меня также выглядит, что request
будет готов к сборке мусора, как только функция initRequest
завершится, то есть, возможно, прежде чем кто-либо из его слушателей будет вызван.
Ответ 2
Насколько я вижу, объект запроса должен существовать только внутри функции initRequest и должен быть помечен для сбора мусора, когда функция завершается.