Заполнение памяти используемое программой.
- Войдите на сайт для отправки комментариев
Пнд, 02/09/2013 - 13:34
import processing.net.*; //Связь с Ethernet клиентом и сервером int html_port = 80; int arduino_port = 82; String IP_arduino = "10.168.2.129"; Server server; Client client; int connect_arduino=0; int connect_server=0; String list; //Символ до которого будем считывать данные byte flag=62; //Переменные с данными float [] fl_data=new float [8]; String str_data[]; //Вывод данных в график float xn=420, xk=420, yn1, yk1, yn2, yk2, yn3, yk3, yn4, yk4; //Интервал графика 4 мин 1 pix. long previous_Grafik = 0; long interval_Grafik = 1000; boolean grafik = true; String climate; void setup() { size(800, 600); background (208, 208, 208); for (int i=1; i<8; i++) { fl_data[i]=0.0; } } void draw() { //Прием данных с ардуино client = new Client(this, IP_arduino, arduino_port); delay (1000); client.write ("GET/Processing 2.0 "); delay (1000); while (client.available()>0){ if (client !=null) { connect_arduino = 1; list = client.readStringUntil(flag); if (list != null) { str_data = split(list, ';'); } } else {connect_arduino = 0;} client.stop (); //Преобразование string в float for (int i=1; i<8; i++){ if (str_data[i] != null) {fl_data[i]=float(str_data[i]);} } } if(millis() - previous_Grafik > interval_Grafik) { previous_Grafik = millis(); print (previous_Grafik); yn1=545-15*(fl_data[1]-15); yn2=545-2.25*(fl_data[2]); yn3=545-15*(fl_data[3]-15); yn4=545-15*(fl_data[4]-15); if (grafik == true) { yk1=yn1; yk2=yn2; yk3=yn3; yk4=yn4; grafik = false; } noStroke (); stroke(208,208,208); line (xk+1, 320, xk+1, 545); line (xk+3, 320, xk+3, 545); line (781, 320, 781, 545); stroke(0); line (xk+2, 320, xk+2, 545); stroke(255, 0, 0); line (xn, yn1, xk, yk1); stroke(0, 125, 255); line (xn, yn2, xk, yk2); stroke(128, 0, 0); line (xn, yn3, xk, yk3); stroke(128, 0, 128); line (xn, yn4, xk, yk4); yk1=yn1; yk2=yn2; yk3=yn3; yk4=yn4; xk=xn; xn++; if (xn > 780) {xn = 420; xk = 420;} } }
Получаем данные с Ethernet, переводим в float, рисуем график. Вроде все элементарно и просто. Все работает. Но через сутки непрерывной работы память используеммая программой увеличивается в разы, и вылетает ошибка OutMemoryError. Выкладываю скетч в оригинале, практически пустой, ни чем не перегруженный. Прошу помоч найти проблеммное место, от которого программа в буфере распухает.
Немного отредактировал
Но проблемма осталась. Память растет.
Client каждый раз создается заново. Либо его надо освобождать, либо создать один раз и использовать. Процессинг не пользую, но, сходу только это. Предполагаю, что метод draw вызывается многократно
Можете попробовать поискать как в процессинге принудительно вызывать Garbage Collector (раз там джава под капотом - должен быть сборщик). И попробовать его дергать время от времени.
Можете попробовать поискать как в процессинге принудительно вызывать Garbage Collector (раз там джава под капотом - должен быть сборщик). И попробовать его дергать время от времени.
Если Вы понимаете разницу между "освободить" память и "остановить" клиента, тогда продолжайте дальше, а если не совсем, тогда посмотрите пример, правда Процессинг 2.0+
Думаю разницу видно и без объяснений.
Если Вы понимаете разницу между "освободить" память и "остановить" клиента, тогда продолжайте дальше, а если не совсем, тогда посмотрите пример, правда Процессинг 2.0+
Думаю разницу видно и без объяснений.
В таком случае читаем комментарии в примере и видим, что там написано примерно следующее:
// Подключение к локальной машине к порту 5204
// Этот пример не будет работать, если сервер в этот момент не слушает порт 5204.
Далее читаем описание к примеру:
Что означает примерно следующее:
Описание: Слиент пытается подключиться к серверу ... Если соединение не установлено, например, хост не найден или сервер не слушает порт, возникает exception.
Т.е. Вы хотите сказать, что запуская пример с параметрами (10 строка):
myClient = new Client( this, ""10.168.2.129"", 82 );
у Вас всё равно возникает exception? При этом Ардуино включен и слушает 82 порт? Пинги идут?
Если идут пинги и всё равно возникает exception, тогда я пас, это уже слишком глубоко для меня.
Мемори лики - это самая "вкуснятина" для мазохистов. Тем более в .net/java которые создавались как-бы для того что-бы они стали невозможны в принципе :(
Попробуйте, для начала, выяснить кто у вас "безобразит". Код работы с сетью или код отрисовки. Попробуйте их поочередно закоментить и покрутить в цикле. Выяснить какая половина "течет".
А в отрисовке, кстати тоже оно бывает. Если верить гуглу. И происходить это может - совсем не по вашей вине.
К примеру:
java - Processing 2.0b8 / Disposing PGraphics objects and memory management - Stack Overflow
Попробуйте еще перед client.stop, следать что-то типа
Вдруг вам сервер закончил свой ответ не символом "перевод строки". Тогда возможно ваш клиент не доконца вычитал "все что пришло", и не освободил какие-то ресурсы. И где-то остается "буффер" который ждет пока данные примутся целиком.
Еще можно client.clear() сделать (совместно с кодом выше).
И еще. попрбуйте Client тоже объявить как локальную переменную. Убрать ее из начала скетча, и вмето
Делать
Что-бы по окончании функции Draw оно понимало что "больше не используем эту переменную" (раз она локальная).
Ну и GC при этом, в профилактических целях - продожать вызывать :)
не решение, но информация http://wiki.processing.org/w/Troubleshooting#Out_Of_Memory_Errors_.28jav...
a System.gc() тут есть? http://www.processing.org/discourse/beta/num_1202914234.html
В таком случае читаем комментарии в примере и видим, что там написано примерно следующее:
// Подключение к локальной машине к порту 5204
// Этот пример не будет работать, если сервер в этот момент не слушает порт 5204.
Далее читаем описание к примеру:
Что означает примерно следующее:
Описание: Слиент пытается подключиться к серверу ... Если соединение не установлено, например, хост не найден или сервер не слушает порт, возникает exception.
Т.е. Вы хотите сказать, что запуская пример с параметрами (10 строка):
myClient = new Client( this, ""10.168.2.129"", 82 );
у Вас всё равно возникает exception? При этом Ардуино включен и слушает 82 порт? Пинги идут?
Если идут пинги и всё равно возникает exception, тогда я пас, это уже слишком глубоко для меня.
Голый код с Clientom грузит память. Код прилагаю.
В таком случае читаем комментарии в примере и видим, что там написано примерно следующее:
// Подключение к локальной машине к порту 5204
// Этот пример не будет работать, если сервер в этот момент не слушает порт 5204.
Далее читаем описание к примеру:
Что означает примерно следующее:
Описание: Слиент пытается подключиться к серверу ... Если соединение не установлено, например, хост не найден или сервер не слушает порт, возникает exception.
Т.е. Вы хотите сказать, что запуская пример с параметрами (10 строка):
myClient = new Client( this, ""10.168.2.129"", 82 );
у Вас всё равно возникает exception? При этом Ардуино включен и слушает 82 порт? Пинги идут?
Если идут пинги и всё равно возникает exception, тогда я пас, это уже слишком глубоко для меня.
Сделал по вышеуказанному примеру.
Что изменилось?Память стоит на месте. Сейчас 17000кБь.
Считывание происходит. Но так же вылетает ошибка, после каждого чтения
Есть еще мысли? Мои увы кончились.
В тему призывается великий мастер MAKSIM, да не падают жухлые листья под ЕГО ноги.
Скорее всего падает на Client.write, попробуйте его в try catch, чтобы определиться.
И еще, если flag сразу не появится в буфере, то readStringUntil вернет null
Скорее всего падает на Client.write, попробуйте его в try catch, чтобы определиться.
дык уже определились. Уже же дали эксепшн. Попытка чтения за концом потока.
Помоему идея "создать один клиент" - не то это направление. Оно же при создании клиента - устанавливает соединение. Послали GET, получили ответ - оборвали соединение. После этого любая попытка что-то прочитать - будет давать этот эксепшн. Что логично - соединения нема, а читать пытаемся.. Метода Client.connect - что-то не видно. Только через конструктор. Значит - каждый раз создавать. И пытатся догадатся почему он не освобождает ресурсы при обрыве коннекшина. Вычитывать все БАЙТЫ пришедшие полностью (а не строки), дергать GC и т.п. Причем байты именно вычитывать, а не "очищать буфер" (что-бы серверная часть могла отослать все что хотела целиком и тоже закрыть коннекшн).
Либо... не обрывать коннешн. Подсоеденились и потихоньку читать до потери пульса, когда байты есть. Но это уже зависит от того что на обратной стороне и как оно будет относится к этому (если с той стороны дуина, то на enc28j60 один одновременный конекшн разрешен, если wiznet - до четерых). Ну и в любом случае "обрыв возможен", так что нужно переподсоединятся.
Что значит "возвращаетт значение void"?
Что значит "возвращаетт значение void"?
Значит "ничего не возвращает". Другими словами это не "функция", а "подпрограмма".
void — Википедия
void — Википедия
Да почему же это смущает? Вы же не пытается что-то получить от функции Client.write(). Просто вызвали - и все.
А сама ошибка у вас на строчку выше.
"Client got end-of-stream."
Вообщем переводим это все как "вы пытаетесь что-то делать с потоком после того как клиент получил символ-конца-потока". Вообщем не нужно пытатся что-то читать/писать в соедининие которое оборванно/закрыто.
А вообще, какой-то он "жутко аскетчиный". Ни тебе проверить состояние соединения, ни event-тов для этого.
Может у вас сервер закрыл соединение, а вы пытаетесь что-то писать в него.
дык уже определились. Уже же дали эксепшн. Попытка чтения за концом потока.
Честно говоря я не вижу подтверждение слов ТС, что "падает после каждого чтения".
Согласно приложенного ТС журнала exception, падение может происходить именно на write, потому я и предложить "обложить" его try catch, чтобы в этом убедиться.
Само чтение уже заключено в try catch, потому ошибки давать не должно. Впрочем могу и ошибаться, Java для меня побочный язык, редко пользую.
Объясню смысл своих догадок:
1. Раньше в первом скрипте ТС он записывал строку GET/Processing... через write на Ардуино (я так это понимаю)
2. Теперь он посылает "1"
Как сервер (Ардуино?) должен реагировать на эти две *разные* строки? Мы не знаем, хотя, может быть скетч сервера на Ардуино и есть, а я просто его не заметил.
А то, к примеру, client.write выведет строку, потом всё, что в try catch нее выполнится, потому что ответа от сервера еще нет, а далее мы проверяем неинициализированную переменную list на null.
ЗЫ На счет соединения, пусть остается как сейчас есть, в примерах я нигде не видел, чтобы Client создавался несколько раз. Для теста это сейчас по барабану и лучше оставить как есть, т.е. создавать один раз в setup.
дык уже определились. Уже же дали эксепшн. Попытка чтения за концом потока.
Честно говоря я не вижу подтверждение слов ТС, что "падает после каждого чтения".
Согласно приложенного ТС журнала exception, падение может происходить именно на write, потому я и предложить "обложить" его try catch, чтобы в этом убедиться.
Само чтение уже заключено в try catch, потому ошибки давать не должно. Впрочем могу и ошибаться, Java для меня побочный язык, редко пользую.
Объясню смысл своих догадок:
1. Раньше в первом скрипте ТС он записывал строку GET/Processing... через write на Ардуино (я так это понимаю)
2. Теперь он посылает "1"
Как сервер (Ардуино?) должен реагировать на эти две *разные* строки? Мы не знаем, хотя, может быть скетч сервера на Ардуино и есть, а я просто его не заметил.
А то, к примеру, client.write выведет строку, потом всё, что в try catch нее выполнится, потому что ответа от сервера еще нет, а далее мы проверяем неинициализированную переменную list на null.
ЗЫ На счет соединения, пусть остается как сейчас есть, в примерах я нигде не видел, чтобы Client создавался несколько раз. Для теста это сейчас по барабану и лучше оставить как есть, т.е. создавать один раз в setup.
Скетч ARDUINO
client.write "1" или client.write "GET/Processing" не имеет значения. Мне GET/Processing был необходим во время отладки скетча ардуино.
client.write заключал в try catch, ошибка не пропала.
Ну вот. Скорее всего на ether.httpServerReply(bfill.position()); соединение было закрыто. Любая попытка после этого read/write - естественно будет заканчиватся фатально.
Нужно подключатся заново. Вообщем, могу только повторить:
>Помоему идея "создать один клиент" - не то это направление.
>Значит - каждый раз создавать. И пытатся догадатся почему он не освобождает ресурсы при обрыве коннекшина. Вычитывать все БАЙТЫ пришедшие полностью (а не строки), дергать GC и т.п
А еще смущает $F в
bfill.emit_p(PSTR(
";$S;$S;$S;$S;$S;$S;$S;$F;>"
)
Уже точно не помню, давно не игрался с enc28j60, но кажись $F означает строку из флеша (или значение типа float, не помню). А у вас climate - это обычный char* . Возможно $S более уместен.
Вообщем-то, это не есть причина текущей проблемы, но потом возмжно нужно будет внимательней сюда присмотрется.
>Голый код с Clientom грузит память. Код прилагаю.
Кстати это тоже "не совсем голый". Голый бы не парсил пришедшие строки.
Или попробуйте вообще вот такое,будет память жрать?
Ну вот. Скорее всего на ether.httpServerReply(bfill.position()); соединение было закрыто. Любая попытка после этого read/write - естественно будет заканчиватся фатально.
Нужно подключатся заново. Вообщем, могу только повторить:
>Помоему идея "создать один клиент" - не то это направление.
>Значит - каждый раз создавать. И пытатся догадатся почему он не освобождает ресурсы при обрыве коннекшина. Вычитывать все БАЙТЫ пришедшие полностью (а не строки), дергать GC и т.п
А еще смущает $F в
bfill.emit_p(PSTR(
";$S;$S;$S;$S;$S;$S;$S;$F;>"
)
Уже точно не помню, давно не игрался с enc28j60, но кажись $F означает строку из флеша (или значение типа float, не помню). А у вас climate - это обычный char* . Возможно $S более уместен.
Вообщем-то, это не есть причина текущей проблемы, но потом возмжно нужно будет внимательней сюда присмотрется.
$F передает данные символьные char/string, в моем случае либо "good", либо "bad".
Вот Вам скетч сервера на Processing
Если кто то желает так же по тестировать клиент, прошу принять участие.
Скетч клиента ниже, я так же продолжаю попытки и наблюдения.
Запустил эти скетчи на процессинг 2.0.2 Win7 x64 всё работает нормально.
Поменял только ip, номер порта на 82. И в клиенте list = null; в setup добавил. А, вру, вместо глобального, сделал Client локальным, как Лешак говорил, это правильно. Если оставить глобальным - выдает exception, но потом работает.
Клиент:
Сервер:
Дальше без меня. Лично я бы заюзал clientEvent & serverEvent и не стал бы на серваке закрывать соединение, как то это по гадски, к тебе пришел гость, ты с ним поговорил, и с какими то словами выдворил его за дверь, а может он еще хотел поговорить. Думаю, что соединение в нормальном обмене должен рвать клиент.
Запустил эти скетчи на процессинг 2.0.2 Win7 x64 всё работает нормально.
Поменял только ip, номер порта на 82. И в клиенте list = null; в setup добавил. А, вру, вместо глобального, сделал Client локальным, как Лешак говорил, это правильно. Если оставить глобальным - выдает exception, но потом работает.
Клиент:
Сервер:
Дальше без меня. Лично я бы заюзал clientEvent & serverEvent и не стал бы на серваке закрывать соединение, как то это по гадски, к тебе пришел гость, ты с ним поговорил, и с какими то словами выдворил его за дверь, а может он еще хотел поговорить. Думаю, что соединение в нормальном обмене должен рвать клиент.
что значит "Работает нормально"? Главная проблема решена? Память не копится?
Ну так запустите и проверяйте. Либо опишите Ваш метод проверки памяти.
Работает, это значит, что на сервере отображаются случайные числа в квадратике.
Ваша схема КЛИЕНТА, так же как и моя копит память. Пол часа работы, с 22000КБ до 42000КБ. Вопрос остался открытым. Проблема накопления памяти не решена.
Буду искать.
Это не моя схема, а Ваша, моя схема - создавать клиента в setup и не рубить соединение на сервере, я уже объяснил почему.
Но Ваша схема, при работе с сервером, выдает ошибку
Которую обойти не получается.
Схема - подразумевает что ей следуют и сервер и клиент. Когда кто-то один из них работает по одной "схеме", а кто-то "по другой" - получается фигня.
Я уже вроде детально расписывал "почему у вас не получается" (№26).
И вы выборочно очень читаете ответы. "не рубить соединение на сервере" - было проигнорировано.
А уж сколько раз было проигнорировано "попробуйте вычитывать ВСЕ байты" (даже код дал для этого #28), "попробуйте вызвать Garbage Collector" - я уже со счета сбился.
Схема - подразумевает что ей следуют и сервер и клиент. Когда кто-то один из них работает по одной "схеме", а кто-то "по другой" - получается фигня.
Как на enc28j60 осуществить не обрыв связи с клиентом? К сожалению в примерах и статьях такой информации не видел.
Я уже вроде детально расписывал "почему у вас не получается" (№26).
Да, я это читал и согласен, но не представляю как зделать иначе.
А уж сколько раз было проигнорировано "попробуйте вычитывать ВСЕ байты" (даже код дал для этого #28), "попробуйте вызвать Garbage Collector" - я уже со счета сбился.
Пробовал, попробую еще раз, вместе с вычитыванием всего что прислал сервер. Результаты напишу.
Вот код, память грузит.
21 строку перенесите в 40-ю, по крайней мере система будет знать, что эта память Вам больше не нужна
зделал. Она там была, я ее в 21 перенес, чтобы уж наверняка перед созданием нового клиента обнулялась.
зделал. Она там была, я ее в 21 перенес, чтобы уж наверняка перед созданием нового клиента обнулялась.
Это неправильно, потому что локальный объект создается, Вы его обнуляете (бессмысленно, поскольку он только что появился), затем создаете. А то, что я написал означает, что "я работу с объектом закончил, можно выносить".
UPD: А после того, как мы сообщили, что "можно выносить", сборщик мусор в своё время эту память освободит. А уж через сколько это произойдет - я не подскажу, моих знаний недостаточно.
зделал. Она там была, я ее в 21 перенес, чтобы уж наверняка перед созданием нового клиента обнулялась.
Это неправильно, потому что локальный объект создается, Вы его обнуляете (бессмысленно, поскольку он только что появился), затем создаете. А то, что я написал означает, что "я работу с объектом закончил, можно выносить".
UPD: А после того, как мы сообщили, что "можно выносить", сборщик мусор в своё время эту память освободит. А уж через сколько это произойдет - я не подскажу, моих знаний недостаточно.
тогда System.gc(); имеет смысл поставить после client=null ?
Кстати println (client); выводит следующее значение: processing.net.Client@12922f6, где 12922f6 каждое новое соединение разное значение.
>тогда System.gc(); имеет смысл поставить после client=null ?
да.
Кстати println (client); выводит следующее значение: processing.net.Client@12922f6, где 12922f6 каждое новое соединение разное значение.
У меня для вас плохие новости :(
Не вы один на это наткнулись :(
Newbie with Out of memory when using client.write() - Processing Forum - так решение и не нашли.
Так же эта проблема находится висит на баг-трекере
Issue 1362 - processing - Recreating Client instance will cause an out-of-memory error - An open source programming language and environment for creating images, animation, and interactions - Google Project Hosting
И как видим - он не отмечена как "решенная". Так что - очень вероятно что это банально "известный баг".
У вас какая версия процессинга, последняя? Если нет - попробуйте на последнюю апгрейднутся, может там пофиксали.
У меня для вас плохие новости :(
Не вы один на это наткнулись :(
Newbie with Out of memory when using client.write() - Processing Forum - так решение и не нашли.
Так же эта проблема находится висит на баг-трекере
Issue 1362 - processing - Recreating Client instance will cause an out-of-memory error - An open source programming language and environment for creating images, animation, and interactions - Google Project Hosting
И как видим - он не отмечена как "решенная". Так что - очень вероятно что это банально "известный баг".
У вас какая версия процессинга, последняя? Если нет - попробуйте на последнюю апгрейднутся, может там пофиксали.
последняя....
Как же мне тогда поступить?
попробуйте, перед client.stop() сделать
если будет ругатся что "нет такого метода unregisterMethod", то это означает что у вас старый процессинг. Тогда вот так:
В общем, решение пока такое, Памяти хватает на 5 часов стабильной работы. Буду использовать планировщик задач Windows для перезапуска приложения, ну и ждать когда пофиксят баг.