LINUX.ORG.RU

Как сделать что б nodejs не тёк?

 , ,


0

5

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

var fs = require('fs');
var ref = require('ref');
var ffi = require('ffi');
var intPtr = ref.refType('int');
var ucharPtrPtr = ref.refType('uchar*');

var MyLib = ffi.Library('MyLib.dll', {
    'GetData': ['bool', ['int', 'int', ucharPtrPtr, intPtr]],
    'ReleaseBuffer': ['void', ['void**']]
})

for (i = 1; i < 100; i++) {
    test();
}

function test() {
    var dataPtr = ref.alloc(ucharPtrPtr);
    var lengthPtr = ref.alloc('int');
    var ret = MyLib.GetData(1, 1, dataPtr, lengthPtr);
    var length = lengthPtr.deref();
    var data = ref.reinterpret(ref.deref(dataPtr), length);
    if (ret) {
        var result = data.toString('base64');
        console.log(result);
    }
    MyLib.ReleaseBuffer(dataPtr);
}

Куда смотреть, что делать?

★★★★★

Он будет теч вечно! Вечно!

deterok ★★★★★
()
Ответ на: комментарий от slackwarrior

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

ya-betmen ★★★★★
() автор топика
Ответ на: комментарий от ya-betmen

Ноду принесли до меня, времени и сил на её выкидывание нет.

Поэтому надо потратить еще больше времени и сил на борьбу с нодопроблемами.

entefeed ☆☆☆
()
Ответ на: комментарий от ya-betmen

Подходов тут больше одного:

«а) Тут нужно все переписать!

б) Локализовать утечки и устранить (скучно, неинтересно, но действенно)

в) Дождаться ответного гудка» (с)

slackwarrior ★★★★★
()
Ответ на: комментарий от entefeed

Ну приносили её дольше 5и часов.

ya-betmen ★★★★★
() автор топика
Ответ на: комментарий от slackwarrior

а) Тут нужно все переписать!

Не знаю как.

б) Локализовать утечки и устранить (скучно, неинтересно, но действенно)

Дебажить ноду? Если это единственный способ то проще её выкинуть.

ya-betmen ★★★★★
() автор топика
Ответ на: комментарий от ya-betmen

выкинуть.

Про что тебе и говорят весь тред. Иди компостируй мозг тому, чье гениальное решение привнесло ноду в проект. Пусть он и решает проблему.

entefeed ☆☆☆
()
Ответ на: комментарий от ya-betmen

Дебажить ноду?

Религия запрещает?

то проще её выкинуть.

Не вижу, почему бы блаародному дону, не выкинуть ноду, если он найдет это удобным.

slackwarrior ★★★★★
()
Ответ на: комментарий от slackwarrior

Религия запрещает?

Проще переписать либу, например.

Не вижу, почему бы блаародному дону, не выкинуть ноду, если он найдет это удобным.

Мне сначала надо понять, чьи кривые руки создают проблему, мои или авторов ноды. Поскольку люди как то из ноды сисшные либы таки дергают, то либо они хирто замалчивают утечки, либо УНВР.

ya-betmen ★★★★★
() автор топика
Ответ на: комментарий от Hertz

Можно ссылку на баг, что б мне было что прицепить на флагшток?

Как я понимаю они просто переехали на новую версию v8.

ya-betmen ★★★★★
() автор топика
Последнее исправление: ya-betmen (всего исправлений: 1)

Совсем не работал с Node.js и почти ничего не помню про сам JS. Но в твоем коде смущает присутствие

MyLib.ReleaseBuffer(dataPtr);
и отсутствие того же для lengthPtr, хотя выделяются одинаково
var dataPtr = ref.alloc(ucharPtrPtr);
var lengthPtr = ref.alloc('int')
так и должно быть?

MadMax
()

а если код (иногда) не доходит до MyLib.ReleaseBuffer(dataPtr); ?

try\catch\finally же нету тут

user_id_68054 ★★★★★
()

я, конечно, node.js не знаю. но, MyLib.ReleaseBuffer(dataPtr) же освобождает память от char**, а не от строки (char*). не правильней ли будет сделать MyLib.ReleaseBuffer(ref.deref(dataPtr)); ?

bolis
()
Ответ на: комментарий от ya-betmen

проще её выкинуть

Растешь не по дням, а по часам.

g0t0
()

Напиши то же самое на сях/плюсцах и убедись что не течёт.

SV0L0CH
()

Если я не ошибаюсь, то освобождать надо там же где выделил, т.е. в MyLib.dll. Поскольку в ноде ты осводил лишь ссылки на участки памяти. А саму память, которую аллоцировала библиотека очищать будет фантомас? Т.о. перед освобождения ссылок в ноде сделай вызов на очищение ссылок в либе (в ноде они будут указывать на NULL-pointer'ы).

Как сказал MadMax, нету вызова MyLib.ReleaseBuffer(lengthPtr);

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

А саму память, которую аллоцировала библиотека очищать будет фантомас?

Спасибо, надо проверить.

Но разве это не общая память приложения, которую может собрать GC? Ссылка то убивается. Кстати вариант когда память выделяли из ноды и передавали указатель в либу тек точно так же.

MyLib.ReleaseBuffer(lengthPtr);

Согласен, но на 100 итерациях указатель на инт не смог бы так засрать память.

ya-betmen ★★★★★
() автор топика
Ответ на: комментарий от ya-betmen

Но разве это не общая память приложения, которую может собрать GC?

Нет. Я честно не спец по ноде, но т.к. проект довольно амбициозен, то для ноды код библиотеки это черный ящик, и наоборот, код ноды для библиотеки также черный ящик.

Это к тому, что мы гадаем тут, а на самом деле у тебя либа, возможно, течет где-то в кишках. Т.к., если бы текла нода, то у тебя утечка была бы на уровне несколько байт на итерацию! Из твоего примера утекло бы порядка 1 кб, ты бы этого и не заметил бы.

Ссылка то убивается.

В ноде да. В либе — неизвестно.

Кстати вариант когда память выделяли из ноды и передавали указатель в либу тек точно так же.

Еще раз. В либе выделяется память под данные (мегабайты) >>> размера на указатели (байты).

---

Угадай с трех раз, что течет у человека: http://stackoverflow.com/questions/24026638/nodejs-node-ffi-memory-leak-varia...

Т.о. проверь верно ли освождает память твоя либа.

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)
Ответ на: комментарий от buddhist

Да как же можно, здесь уже выразились эксперты и выяснили что во всём виноват node.

invokercd ★★★★
()
Ответ на: комментарий от ya-betmen

Но разве это не общая память приложения, которую может собрать GC?

А если бы ты читал книжки по C/C++, то знал бы, что память, выделенная там не может быть просто так очищена GC из ноды.

g0t0
()

У меня вот тоже был амбициозный проект на ноде. Признаться все шло гладко, пока не понадобилось общаться с сишными либами. Тоже нашел node-ffi, оценил кучу шлака, что придется привнести в проект, плюнул и откатился на чистую сишечку и lua

makoven ★★★★★
()

Может, это твоя либа течет? Смотреть? Смотреть профайлерами.

menangen ★★★★★
()
Ответ на: комментарий от makoven

А нативные c++ node модули написать было не судьба? Там делов то часа на 2. Тупо написать обёртки к своему си коду.

menangen ★★★★★
()
Ответ на: комментарий от g0t0

А можно ссылочку, на то место где это написано, я когда то тыкал c++, и память которая выделялась в библиотеке можно было очистить из приложения. У меня с данным куском памяти связан буфер, ссылка на который прибита, почему GC не может её собрать?

ya-betmen ★★★★★
() автор топика
Ответ на: комментарий от ya-betmen

почему GC не может её собрать?

Потому что он эту память не разбирал?

bj
()
Ответ на: комментарий от menangen

К тому моменту уже прошло несколько месяцев как StrongLoop начал кормить нас блогозаписями скорого наступления «version 0.12» (а воз и ныне там), с каждой блогозаписью уменьшая количество планируемых фич. Гугл окончательно забросил старую версию v8, которую и по сей пользует нода. А потом из проекта свалил Диджей Головайчик и я понял что это конец )

makoven ★★★★★
()
Ответ на: комментарий от ya-betmen

А можно ссылочку, на то место где это написано, я когда то тыкал c++, и память которая выделялась в библиотеке можно было очистить из приложения. У меня с данным куском памяти связан буфер, ссылка на который прибита, почему GC не может её собрать?

GC работает с HEAP. Он понятия не имеет чем библиотека выделяла память под буфер и чем ее освобождать. Чтобы освобождение шло через GC, библиотека должна через v8 нативный объект сделать, и через него же память выделить. А так надо дергать деалокатор библиотеки.

Чтобы это понять, не надо читать секретных методичек, достаточно подумать и догадаться, что аллокаторы разные.

Сама нода не течет, инфа 146%.

Vit ★★★★★
()
Ответ на: комментарий от ya-betmen

Потому, что для него это void*. Дальше объяснять?

g0t0
()
Ответ на: комментарий от makoven

и я понял что это конец )

Боюсь, такой удачи этот мир не заслужил.

tailgunner ★★★★★
()

Сразу говорю, я абсолютно не знаю жабаскрипта. Но ты вызываешь какой-то alloc, который, как я понимаю, выделяет память, которую, как я понимаю, ты освобождаешь ReleaseBuffer(), но ты освобождаешь только dataPtr, а памть выделяешь еще для lengthPtr.

nikolnik ★★★
()

Ничего себе какая концентрация икспертов на один тред.

Ubuntu1210
()
Ответ на: комментарий от nikolnik

Я уже отписался, что очевидно что за 100 итераций утекание на целых числах было бы незаметно. Явно не освобождается содержимое буфера.

ya-betmen ★★★★★
() автор топика

Как сделать что б nodejs не тёк?

Не возбуждать его, пользуясь им?

Oxdeadbeef ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.