>Кстати, а что это дает? Не хочется быть просто попугаем :)
Как я понял происходит примерно следующие:
Когда вы создаете объект Client, то первым параметром вы передаете ему this. В данный момент это ваш PApplet (вообщем главный объект вашего приложения, ваше окошко).
Этот клиент регистриует в PApplet свой метод Dispose (это метод который должен вызватся при разрушении объекта, что-бы освободить все ресурсы и т.п.). Что-бы PApplet, когда завершит свою работу (например пользователь нажал "закрыть"), мог сообщить всем кто попросил об этом (зарегистрировался у него) что "ребята, нас попросили с вещами на выход, собирайте манатки".
Вот.... :)
Теперь вам ваш объект Client - стал не нужен. Вы вызвали .stop(), сделали client=null. Но... PApplet про это ничего не знает. Client забыл ему сообщить что "все, меня уже зарахакирили, я уже все что нужно - освободил". Поэтому в PApplet по прежнему осталась ссылка на экземляр клиента. А раз на него "есть ссылка", то уборщик мусора, не может его удалить. Так как видит, что PApplet-у он еще может пригодится.
Мы же, за него сказали PApplet-у типа "забудь про этот объект" :) Не будет на него ссылки - он станет "никому не нужный", и GC, проходя мимо, отправит его в астрал. Освободит память.
Ну вот примерно так.
Правда я выкинул из того что там советовали проверку if (host != null && thread != null)... лениво вникать нафиг она нужна. Тем более что эти host и thread - снаружи все равно скорее всего недоступны
>Кстати, а что это дает? Не хочется быть просто попугаем :)
Как я понял происходит примерно следующие:
Когда вы создаете объект Client, то первым параметром вы передаете ему this. В данный момент это ваш PApplet (вообщем главный объект вашего приложения, ваше окошко).
Этот клиент регистриует в PApplet свой метод Dispose (это метод который должен вызватся при разрушении объекта, что-бы освободить все ресурсы и т.п.). Что-бы PApplet, когда завершит свою работу (например пользователь нажал "закрыть"), мог сообщить всем кто попросил об этом (зарегистрировался у него) что "ребята, нас попросили с вещами на выход, собирайте манатки".
Вот.... :)
Теперь вам ваш объект Client - стал не нужен. Вы вызвали .stop(), сделали client=null. Но... PApplet про это ничего не знает. Client забыл ему сообщить что "все, меня уже зарахакирили, я уже все что нужно - освободил". Поэтому в PApplet по прежнему осталась ссылка на экземляр клиента. А раз на него "есть ссылка", то уборщик мусора, не может его удалить. Так как видит, что PApplet-у он еще может пригодится.
Ну вот примерно так.
Правда я выкинул из того что там советовали проверку if (host != null && thread != null)... лениво вникать нафиг она нужна. Тем более что эти host и thread - снаружи все равно скорее всего недоступны
15 минут - полет нормальный. память так и есть 23770КБ.
Да зачем так долго? Сделайте delay() поменьше на порядок. Вначале "без лечения" (что-бы убедится что проблема воспроизводится точно так же,тлько быстрее), а потом "с лечением".
Да зачем так долго? Сделайте delay() поменьше на порядок. Вначале "без лечения" (что-бы убедится что проблема воспроизводится точно так же,тлько быстрее), а потом "с лечением".
я дома, так что поменять не смогу ни чего. Только мониторить есть возможность. Кстати, пока все Ок, прошло уже 2.5 часа.
дома любимая супруга и две дочери, не до процессингов.
Да. Это тоже неплохо память умеет переполнять. Тоже иногда папу могут высадить в состояние SystemOverflow :) И никакой unregisterMethod тут не поможет :)
Строка 20 - 100% лишняя. Убрав ее строки 19 и 21-ть можно объединить в одну.
Строка 48 - 95% лишняя. Это мы уже перебирали "от отчаяния". По идее оно само, по выходу из функции, должно понимать что "переменная больше не нужна" и уничтожать ее. Так как было не понятно почему оно ее не уничтожает, то мы фактически сделали "повторяем для дебилов: переменная нам не нужна". Но, так как мы нашли почему переменная не удалялась, то скорее всего явное client=null - уже не нужно.
Строка 49 - 60% лишняя. По идее, System.gc(), время от времени вызывается автоматически сам. Это было опять-таки "от отчаяния". Поэтому - можно попробовать убрать. В результате потребление памяти может начать чуть-чуть расти, но потом - освободится. Вообщем "мусорщик" будет вызыватся чуть-чуть реже. Зато - без усилий с нашей стороны.
Строка 29,30 должны идти после while, а не внутри его. Просто "как-то не логично". По идее нам же нужно "вычитать данные", а потом обрывать коннекшн. А так у вас получилось "прочитали один байт и сразу оборвали". Если вы "так и хотели", то зачем там while? Более логичным был-бы if
Строка 20 - 100% лишняя. Убрав ее строки 19 и 21-ть можно объединить в одну.
Строка 48 - 95% лишняя. Это мы уже перебирали "от отчаяния". По идее оно само, по выходу из функции, должно понимать что "переменная больше не нужна" и уничтожать ее. Так как было не понятно почему оно ее не уничтожает, то мы фактически сделали "повторяем для дебилов: переменная нам не нужна". Но, так как мы нашли почему переменная не удалялась, то скорее всего явное client=null - уже не нужно.
Строка 49 - 60% лишняя. По идее, System.gc(), время от времени вызывается автоматически сам. Это было опять-таки "от отчаяния". Поэтому - можно попробовать убрать. В результате потребление памяти может начать чуть-чуть расти, но потом - освободится. Вообщем "мусорщик" будет вызыватся чуть-чуть реже. Зато - без усилий с нашей стороны.
Строка 29,30 должны идти после while, а не внутри его. Просто "как-то не логично". По идее нам же нужно "вычитать данные", а потом обрывать коннекшн. А так у вас получилось "прочитали один байт и сразу оборвали". Если вы "так и хотели", то зачем там while? Более логичным был-бы if
import processing.net.*;
//Связь с Ethernet клиентом и сервером
int arduino_port = 80; // порт сервера подключения
String IP_arduino = "127.0.0.1"; //IP адрес сервера к которому подключаетесь.
int list;
void setup()
{
size (100, 100);
background(255);
}
void draw()
{
//Прием данных с ардуино
Client client = new Client(this, IP_arduino, arduino_port);
delay (1000);
client.write ("1");
delay (1000);
try {
while (client.available ()>0)
{
list = client.read();
}
this.unregisterMethod("dispose",client);
client.stop();
}
catch (Exception e) {
list = 0;
}
background(255);
textSize(32);
fill (0);
if (list == 0) {
println ("Null");
text ("Null", 10, 50);
}
if (list != 0) {
println (list);
text (list, 10, 50);
}
System.gc();
}
Мы сначала "освобождаем" объект, а потом стопим уже освобожденный объект. Я допускаю, что это работает, но логика непонятна. Во всяком случае мне непонятна.
Мы сначала "освобождаем" объект, а потом стопим уже освобожденный объект. Я допускаю, что это работает, но логика непонятна. Во всяком случае мне непонятна.
Нет. Вы не поняли "почему проблема". unregisterMethod - не "освобождает объект". А "особождает ссылку" внутри PApplet.
Смотрите. А нас есть два объекта. a и b. Объект a имеет ссылку на объект b. Где-то раньше в коде было сделанно что-то типа a.extReff=b;
Потом мы решили что b нам больше не нужен. И сделали b=null; Обнулили "переменную b". Но, на сам объект по прежнему осталась живая ссылку внутри объекта a. И мусорщик никак не может удалить объект с концами. Поэтому мы делаем что-то типа
a.extReff=null; // сказали объекту a забыть о существовании b
b.stop();// сами еще поработали с объектом
b=null; // нам тоже уже не нужна ссылка на этот объект
// все раз "никому он не нужен", мусорщик его может его выкинуть в помойку.
Потому что метод unregisterMethod принимает объект который нужно "отцепить". Если вы передадите ему null, то как он узнает "кого отцеплять"? Он же не про один объект помнит.
Но, в принципе, можно и после client.stop() попробовать вызвать. Просто перед - оно ближе к естественной логики. По хорошему сам client должен был сделать отцепляние. Внутри stop(). Мы как бы "сделали за него работу". "Дописали" начало метода stop()
А еще, внутри метода stop() вызывается dispose(). То есть фактически объект приходит "в нерабочее состояние". Лично мне было проще вызвать ungregister с еще "заведомо правильным объектом", чем выяснять в деталях реализацию unregisterMethod, может он в процессе де-регистрации еще что-то пытается вызвать у client()-та, к примеру сообщить ему "все чувак, я больше за тобой не слежу". И неведомо как client у которого уже вызвали stop() сможет это корректно обработать.
Если любопытно - можете попрбовать вызвать после stop() (но в любом случае до client=null, если вы его делаете).
при выполнении метода экземпляра "stop" (instance method) ccылка на экземпляр "сlient" не может измениться, в том числе не может об-null-иться
Хм... за кого вы меня держите? :)
А вот может быть примерно такой unsubscribeMethod()
void unsibscribeMethod(Object obj){
if(obj is IUnsubscrible){
((IUnsubscrible))obj).notifyAboutUnsubscribe(); // сообщаем объекту что он больше не подписан
}
// удаляем объект из внутренних ссылок
internalRefs.remove(obj);
.....
}
Далее.
А в client.notifyAboutUnsubscribe() используются какие-то внутрении поля, разрушаемые при вызове stop()/dispose()
В таком случае - вызов после stop() - закончится проблемами.
Согласен, такой "вычурный код", куча "взаимных callback" - это фигня архитектуры. Но, увы, и не такое видали.
Так что я предпочитаю - не хмурить мозг "как оно там на самом деле", и что-то делать с объектом только в заведомо рабочем состоянии. Если я вижу что у объекта уже был вызван dispose() - то я инстинктивно ставлю себе в голове галочку "все, больше с этим объектом работать нельзя". Хотя может быть он бы и мог еще "потрепыхатся", зачем мне такие риски, тем более в ситуации когда код запускается другим человеком удаленно и итерация проверки занимает часы/дни? Разве не логично что я выберу "самый безопастный вариант"?
попробуйте, перед client.stop() сделать
если будет ругатся что "нет такого метода unregisterMethod", то это означает что у вас старый процессинг. Тогда вот так:
Запустился первый вариант (процессинг сегодня переустанавливал т.к. винда чистая).
Кстати, а что это дает? Не хочется быть просто попугаем :)
А вы, все-таки, попробуйте рецепт из #49. Это попытка применить "решение" из Issue 1362 - processing - Recreating Client instance will cause an out-of-memory error, только не "внутри библиотеки", а "снаружи" (что-бы не разбиратся как их там в процессинге перекомпиливать, не ставить эклипс, SDK и т.п.).
А вы, все-таки, попробуйте рецепт из #49. Это попытка применить "решение" из Issue 1362 - processing - Recreating Client instance will cause an out-of-memory error, только не "внутри библиотеки", а "снаружи" (что-бы не разбиратся как их там в процессинге перекомпиливать, не ставить эклипс, SDK и т.п.).
Уже пробую, как 10 минут. Пока результат положительный (тьфу тьфу тьфу). Память держится в районе 23780КБ
>Кстати, а что это дает? Не хочется быть просто попугаем :)
Как я понял происходит примерно следующие:
Когда вы создаете объект Client, то первым параметром вы передаете ему this. В данный момент это ваш PApplet (вообщем главный объект вашего приложения, ваше окошко).
Этот клиент регистриует в PApplet свой метод Dispose (это метод который должен вызватся при разрушении объекта, что-бы освободить все ресурсы и т.п.). Что-бы PApplet, когда завершит свою работу (например пользователь нажал "закрыть"), мог сообщить всем кто попросил об этом (зарегистрировался у него) что "ребята, нас попросили с вещами на выход, собирайте манатки".
Вот.... :)
Теперь вам ваш объект Client - стал не нужен. Вы вызвали .stop(), сделали client=null. Но... PApplet про это ничего не знает. Client забыл ему сообщить что "все, меня уже зарахакирили, я уже все что нужно - освободил". Поэтому в PApplet по прежнему осталась ссылка на экземляр клиента. А раз на него "есть ссылка", то уборщик мусора, не может его удалить. Так как видит, что PApplet-у он еще может пригодится.
Мы же, за него сказали PApplet-у типа "забудь про этот объект" :) Не будет на него ссылки - он станет "никому не нужный", и GC, проходя мимо, отправит его в астрал. Освободит память.
Ну вот примерно так.
Правда я выкинул из того что там советовали проверку if (host != null && thread != null)... лениво вникать нафиг она нужна. Тем более что эти host и thread - снаружи все равно скорее всего недоступны
>Кстати, а что это дает? Не хочется быть просто попугаем :)
Как я понял происходит примерно следующие:
Когда вы создаете объект Client, то первым параметром вы передаете ему this. В данный момент это ваш PApplet (вообщем главный объект вашего приложения, ваше окошко).
Этот клиент регистриует в PApplet свой метод Dispose (это метод который должен вызватся при разрушении объекта, что-бы освободить все ресурсы и т.п.). Что-бы PApplet, когда завершит свою работу (например пользователь нажал "закрыть"), мог сообщить всем кто попросил об этом (зарегистрировался у него) что "ребята, нас попросили с вещами на выход, собирайте манатки".
Вот.... :)
Теперь вам ваш объект Client - стал не нужен. Вы вызвали .stop(), сделали client=null. Но... PApplet про это ничего не знает. Client забыл ему сообщить что "все, меня уже зарахакирили, я уже все что нужно - освободил". Поэтому в PApplet по прежнему осталась ссылка на экземляр клиента. А раз на него "есть ссылка", то уборщик мусора, не может его удалить. Так как видит, что PApplet-у он еще может пригодится.
Ну вот примерно так.
Правда я выкинул из того что там советовали проверку if (host != null && thread != null)... лениво вникать нафиг она нужна. Тем более что эти host и thread - снаружи все равно скорее всего недоступны
15 минут - полет нормальный. память так и есть 23770КБ.
Оставляю на ночь, утром отпишусь.
Оставляю на ночь, утром отпишусь.
Да зачем так долго? Сделайте delay() поменьше на порядок. Вначале "без лечения" (что-бы убедится что проблема воспроизводится точно так же,тлько быстрее), а потом "с лечением".
Оставляю на ночь, утром отпишусь.
Да зачем так долго? Сделайте delay() поменьше на порядок. Вначале "без лечения" (что-бы убедится что проблема воспроизводится точно так же,тлько быстрее), а потом "с лечением".
я дома, так что поменять не смогу ни чего. Только мониторить есть возможность. Кстати, пока все Ок, прошло уже 2.5 часа.
я дома, так что поменять не смогу ни чего. Только мониторить есть возможность. Кстати, пока все Ок, прошло уже 2.5 часа.
А дома что мешает скачать и запустить Processing? ;)
я дома, так что поменять не смогу ни чего. Только мониторить есть возможность. Кстати, пока все Ок, прошло уже 2.5 часа.
А дома что мешает скачать и запустить Processing? ;)
дома любимая супруга и две дочери, не до процессингов.
дома любимая супруга и две дочери, не до процессингов.
Да. Это тоже неплохо память умеет переполнять. Тоже иногда папу могут высадить в состояние SystemOverflow :) И никакой unregisterMethod тут не поможет :)
Отчитываюсь.
Работа Processinga в режиме Клиент на протяжении 16 часов проблемм увеличения памяти не выявила.
Выкладываю работоспособный минимализированный код.
Строка 20 - 100% лишняя. Убрав ее строки 19 и 21-ть можно объединить в одну.
Строка 48 - 95% лишняя. Это мы уже перебирали "от отчаяния". По идее оно само, по выходу из функции, должно понимать что "переменная больше не нужна" и уничтожать ее. Так как было не понятно почему оно ее не уничтожает, то мы фактически сделали "повторяем для дебилов: переменная нам не нужна". Но, так как мы нашли почему переменная не удалялась, то скорее всего явное client=null - уже не нужно.
Строка 49 - 60% лишняя. По идее, System.gc(), время от времени вызывается автоматически сам. Это было опять-таки "от отчаяния". Поэтому - можно попробовать убрать. В результате потребление памяти может начать чуть-чуть расти, но потом - освободится. Вообщем "мусорщик" будет вызыватся чуть-чуть реже. Зато - без усилий с нашей стороны.
Строка 29,30 должны идти после while, а не внутри его. Просто "как-то не логично". По идее нам же нужно "вычитать данные", а потом обрывать коннекшн. А так у вас получилось "прочитали один байт и сразу оборвали". Если вы "так и хотели", то зачем там while? Более логичным был-бы if
Строка 20 - 100% лишняя. Убрав ее строки 19 и 21-ть можно объединить в одну.
Строка 48 - 95% лишняя. Это мы уже перебирали "от отчаяния". По идее оно само, по выходу из функции, должно понимать что "переменная больше не нужна" и уничтожать ее. Так как было не понятно почему оно ее не уничтожает, то мы фактически сделали "повторяем для дебилов: переменная нам не нужна". Но, так как мы нашли почему переменная не удалялась, то скорее всего явное client=null - уже не нужно.
Строка 49 - 60% лишняя. По идее, System.gc(), время от времени вызывается автоматически сам. Это было опять-таки "от отчаяния". Поэтому - можно попробовать убрать. В результате потребление памяти может начать чуть-чуть расти, но потом - освободится. Вообщем "мусорщик" будет вызыватся чуть-чуть реже. Зато - без усилий с нашей стороны.
Строка 29,30 должны идти после while, а не внутри его. Просто "как-то не логично". По идее нам же нужно "вычитать данные", а потом обрывать коннекшн. А так у вас получилось "прочитали один байт и сразу оборвали". Если вы "так и хотели", то зачем там while? Более логичным был-бы if
Если я правильно понимаю, то эти строки поставлены наоборот:
Мы сначала "освобождаем" объект, а потом стопим уже освобожденный объект. Я допускаю, что это работает, но логика непонятна. Во всяком случае мне непонятна.
Мы сначала "освобождаем" объект, а потом стопим уже освобожденный объект. Я допускаю, что это работает, но логика непонятна. Во всяком случае мне непонятна.
Нет. Вы не поняли "почему проблема". unregisterMethod - не "освобождает объект". А "особождает ссылку" внутри PApplet.
Смотрите. А нас есть два объекта. a и b. Объект a имеет ссылку на объект b. Где-то раньше в коде было сделанно что-то типа a.extReff=b;
Потом мы решили что b нам больше не нужен. И сделали b=null; Обнулили "переменную b". Но, на сам объект по прежнему осталась живая ссылку внутри объекта a. И мусорщик никак не может удалить объект с концами. Поэтому мы делаем что-то типа
Нет. Вы не поняли "почему проблема". unregisterMethod - не "освобождает объект". А "особождает ссылку" внутри PApplet.
Переформулирую, почему нужно сначала "отцепить" объект, а потом его остановить, почему не наоборот?
Вполне допускаю, что в данном случае - безразлично, однако если следовать логике..
Потому что метод unregisterMethod принимает объект который нужно "отцепить". Если вы передадите ему null, то как он узнает "кого отцеплять"? Он же не про один объект помнит.
Но, в принципе, можно и после client.stop() попробовать вызвать. Просто перед - оно ближе к естественной логики. По хорошему сам client должен был сделать отцепляние. Внутри stop(). Мы как бы "сделали за него работу". "Дописали" начало метода stop()
А еще, внутри метода stop() вызывается dispose(). То есть фактически объект приходит "в нерабочее состояние". Лично мне было проще вызвать ungregister с еще "заведомо правильным объектом", чем выяснять в деталях реализацию unregisterMethod, может он в процессе де-регистрации еще что-то пытается вызвать у client()-та, к примеру сообщить ему "все чувак, я больше за тобой не слежу". И неведомо как client у которого уже вызвали stop() сможет это корректно обработать.
Если любопытно - можете попрбовать вызвать после stop() (но в любом случае до client=null, если вы его делаете).
Ок, останемся при своих. Спасибо за информацию, тема мне больше не интересна
>> client.stop();
при выполнении метода экземпляра "stop" (instance method) ccылка на экземпляр "сlient" не может измениться, в том числе не может об-null-иться
>> client.stop();
при выполнении метода экземпляра "stop" (instance method) ccылка на экземпляр "сlient" не может измениться, в том числе не может об-null-иться
Хм... за кого вы меня держите? :)
А вот может быть примерно такой unsubscribeMethod()
Далее.
А в client.notifyAboutUnsubscribe() используются какие-то внутрении поля, разрушаемые при вызове stop()/dispose()
В таком случае - вызов после stop() - закончится проблемами.
Согласен, такой "вычурный код", куча "взаимных callback" - это фигня архитектуры. Но, увы, и не такое видали.
Так что я предпочитаю - не хмурить мозг "как оно там на самом деле", и что-то делать с объектом только в заведомо рабочем состоянии. Если я вижу что у объекта уже был вызван dispose() - то я инстинктивно ставлю себе в голове галочку "все, больше с этим объектом работать нельзя". Хотя может быть он бы и мог еще "потрепыхатся", зачем мне такие риски, тем более в ситуации когда код запускается другим человеком удаленно и итерация проверки занимает часы/дни? Разве не логично что я выберу "самый безопастный вариант"?