Я недавно выпустил свой социальный рисунок Draw.wtf Где вы соревнуетесь друг с другом, рисуя вещи и оцениваемся по модели машины обучения. Пока я получил много положительных отзывов, так как я выпустил его, я также быстро обнаружил, что что-то был неправ. Бэкэнда для игры написана в Гнездо (Узел) и размещены на Heroku (который я могу действительно рекомендовать, их свободный уровень отлично подходит для страстных проектов). Но, глядя на использование памяти в обзор метрики, я мог бы ясно видеть, что вещи, которые мы не в порядке:
Там не было никаких способов использовать эту большую память, поэтому было ясно, что у меня была утечка памяти .
Утечка памяти заключается в том, когда приложение использует память (RAM), не отпустив его. Наиболее современный (высокий уровень) языки программирования сегодня реализуют какую-то автоматическую очистку неиспользуемой памяти и узла использует что-то называемое A «Мусорный коллектор» Отказ Ради этой истории отладки, это все, что вам нужно знать!
Вернуться к проблеме в draw.wtf! Я почти только работал на языках с сборкой мусора, поэтому, начнем устранить эту проблему, у меня не имел опыта с нахождением утечек памяти. Моя первая мысль была просто прокрутить код и найти проблему Бууота безрезультатно. Я понятия не имел, где в коде ошибок может жить, и так как мы не делаем никакой ручной обработки памяти там не должен существуют какие-либо ошибки!:(
Следующим шагом было достичь наиболее распространенного инструмента в каждом разработчике Toolbox: Google!
Я читаю много Из статей о нахождении проблем памяти в узле, но никто не привел меня близко к решению. Наконец я нашел статью, которая рекомендовала библиотеку Узел-memwatch который выглядел многообещающим! К сожалению, это не обновлено в течение 7 лет …
Открытый источник для спасения! 🚀
Глядя на Формы узла-Memwatch мы можем попробовать найти тот, который все еще поддерживается, и после просмотра пары я оказался Эта вилка от Airbnb.
Вернитесь в код, который я начал с тестирования библиотеков Куча отличается Бег Новый Memwatch. Heapdiff (); и Heapdiff.end (); который выводит до и после использования памяти. И конечно, достаточно, я вижу, что память растут примерно на 2 МБ для каждого раунда в игре.
Одна вещь, которую я обнаружил, когда тестирование это было то, что память не Расти, когда я ничего не нарисовал! 🤔 Это было действительно здорово, так как он сузился, где в коде в этом вопросе. С этими знаниями я переместил дифференцированные функции кучи на пару разных мест, где обрабатываются нарисованные линии, и это привело меня к функции, которая была протекающей памятью: вычисление баллов.
Для расчета баллов у меня есть модель обучения машины, обученной Azure Custom Vision а затем пробегает его локально с Tensorflow Отказ Вот реализация этой функции расчета, с проблемой утечки памяти не повреждена:
async function calculate(pixels) {
const inputs =
pixels instanceof tf.Tensor
? pixels
: this._preprocess(tf.browser.fromPixels(pixels, 3))
const outputs = await this.model.execute(inputs, null)
const arrays = !Array.isArray(outputs)
? await outputs.array()
: Promise.all(outputs.map(t => t.array()))
const result = Array.isArray(arrays[0])
? arrays[0].map((x, i) => ({ probability: x, tag: this.tags[i] }))
: []
return result
}
Вы видите проблему? (Это не в _preprocess Функция).
Я уверен, что несмотря ни на что я смотрел на этот код, так что дальше я погрузился в документацию Tensorflow.js, где я нашел Этот маленький самородок мудрости:
«При использовании Backend WebGL TF. Память тензорной памяти должна быть безупречна (не достаточно, чтобы позволить TF. Tensor выйдет из прицела для его памяти, которая будет выпущена). “
Аааа, решение! С этим было не очень трудно прочитать дополнительную документацию и в конечном итоге с расчетом счет, который работает:
async function calculate(pixels) {
const inputs = tf.tidy(() => {
return pixels instanceof tf.Tensor
? pixels
: this._preprocess(tf.browser.fromPixels(pixels, 3))
})
const outputs = await this.model.execute(inputs, null)
const arrays = !Array.isArray(outputs)
? await outputs.array()
: Promise.all(outputs.map(t => t.array()))
const result = Array.isArray(arrays[0])
? arrays[0].map((x, i) => ({ probability: x, tag: this.tags[i] }))
: []
inputs.dispose()
Array.isArray(outputs) ? outputs.forEach(o => o.dispose()) : outputs.dispose()
return result
}
tf.tidy () автоматически располагает любой тф Тензор Создано внутри, а потом я бегу вручную утилизировать () На любом тензоре я должен создать за пределами этого. И это все! Теперь память больше не протекает:
Чтобы закончить это, если вы собираетесь взять что-нибудь с вами из этого поста, я думаю, что это должно быть так Узел-memwatch это довольно хороший инструмент для устранения неисправностей проблем с памятью. Если есть что-то, что вы должны не Возьмите с собой, это, вероятно, образцы кода. Я понятия не имею, если они хорошие, плохие или уродливые 😅
Вы бы решили это другим способом? Дай мне знать в комментариях!
Оригинал: “https://dev.to/awnton/troubleshooting-nodejs-memory-leaks-with-node-memwatch-5fpp”