Как очистить память от локальной переменной
- Войдите на сайт для отправки комментариев
Втр, 18/12/2012 - 17:21
Как очистить память от локальной переменной типа String, которая генерируется динамически внутри функции? после выполнения функции эта информация больше не нужна, а память, отведенная под эту строку, остается занятой.
память под локальные переменные отводятся в стеке и при выходе из функции пропадает
что касается класса String , то это обьект, и ИМХО задача програмиста удалять его , если он не нужен
как правильно удалить этот тип объекта?
delete имя_переменной; выдает ошибку.
если переменная типа String глобальная, можно ли ее удалить?
если сделать имя_переменной=""; то переменная становится пустой, но память, занятая ею раньше остается забитой. можно ли очистить занимаемую ею память?
Полагаю так
Если вы в функции создадите
String A;
без конструктора new , то заботится не о чем , и конструктор и деструктор будет создан при компиляции, обьект будет уничтожен при выходе из функции, Не уверен но возможно весь обьект так же будет расположен в стеке, поэтому заботится не о чем, более знающие поправят.
Что касается String то нет под рукой обьявления класса, нахожусь не на работе. Но если создавать String конструктором new то надо вызывать деструктор, в котором описано удаление буфера
Глобальный обьект ( такой же String A; но вне функции )полагаю удалить нельзя он при компиляции описывается в памяти,нечто вроде static. Подозреваю что присвоение стрингу A="" даст освобождение памяти. не обьекта, но на величину буфера обекта под строку.
косвенное подтверждение всего сказанного мною кроме последнего -
http://stackoverflow.com/questions/9805829/arduino-c-destructor
Глобальный обьект ( такой же String A; но вне функции )полагаю удалить нельзя он при компиляции описывается в памяти,нечто вроде static. Подозреваю что присвоение стрингу A=""
Если не поможет (думаю это так, не нашел вколде что бы размер буффера уменьшался, вижу только увеличение, если не хватает), то можно попытася A=0;
Внутри Wstring.cpp это выглядит так:
Что, по идее должно вызвать invalidate();
Который, в свою очередь:
то есть "то что нам нужно".
Но, в приличных конторах, за такие финты дают в глаз :) Так как совершенно не очевидно что делает A=0;, во вторых мы полагаемся на конкретную реализацию интерфейса (про которую не должны ничего знать). Если в будущем поменяют внутреню реализацию метода присваивания (имеют полное право) и он перестанет при нуле вызывать методо invalidate(), то тот кто будет чинить образовавшийся баг - поседеет.
Уж лучше полезть сделать свой форк от WString.h и добавить метод с названием типа resetBuff() (а в нем вызывать invalidate()). В таком случае если будет апдейт, то тот кто будет обновлять форк, будет вынужден посмотреть не исчезли метод invalidate() и обязан убедится что он продолжает делать то же самое.
Ну а еще, как вариант, забить болт на String и пользоватся обычными сишными строками, самому выделить, самому освобождать и не тянуть за собой громадное количестве методов, которые редко когда используются все сразу :)
Спасибо за развернутый ответ =) завтра попробую сделаь с присвоением нуля.
С локальными переменными теперь понятно, а вот возможно ли уменьшить размер глобальной переменной?
с присвоением "" память не освобождается.
в скетче читаю в стринг (глобальную) ком-порт, для последующего разбора строки. если приходит много данных, то остается занятая память под переменную и очистить ее пока не удается.
Ну можно еще так попытася извратится - пронаследоватся от String
Выводит
Но, IMHO сликом много возни (потом еще операторы доопределять что-бы было удобно и т.п.)
Спасибо, интересное решение) завтра буду пробовать. Но возни действительно много.
А может быть Вы сможете объяснить мне как работает эта функция?
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
долго думал, но так и не смог понять
Вроде работает с нулем.
Выдает
Так что память явно освобожадется, но это ОЧЕНЬ плохой стиль программирования :)
С локальными переменными теперь понятно, а вот возможно ли уменьшить размер глобальной переменной?
Да с локальными вообще ничего мудрить не нужно. При выходе из функции вызовется деструктор, а он вызовет free - и все. Никаких движений по этому поводу от нас - не требуется.
Танцы с нулем, наследниками класса и проч. мдень - это требуется только с глобальными переменными. Я ведь и примеры показывал с глобальными переменными.
Спасибо, интересное решение) завтра буду пробовать. Но возни действительно много.
А может быть Вы сможете объяснить мне как работает эта функция?
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
долго думал, но так и не смог понять
Видите ключевое слово extern? Это значит что __heap_start и __brkval обявлены гдето-то в другом месте (и кто-то их должен был перед этим заполнить) . Насколько я понимаю это куча и стек.
И кто-то их должен был заполнить раньше. Либо их кто-то заполняет внутрях ардуино-библиотек-дебрей, либо... нужно воспользоватся функцией типа check_mem(). Подозреваю что код вы утащили с http://playground.arduino.cc/Code/AvailableMemory, там она приведена чуть выше (правда имена переменных чуток другие).
Но... у меня она простым copy-paste не заработала... я и не стал вникать в ее тонкости. Хватило avaliableMemory() (я ее использовал в прошлом посте).
Кстати, иногда еще полезно начинать знакомство с форумом начиная с прекрепленных веток
Вставка программного кода в тему/комментарий
Это намек :)
С кодом исправлюсь) а эта функция попалась мне где-то давно и я ее часто использую.
то, что эти переменные берутся извне - это я понимаю. а вот что делается здесь - понять пока не могу.
в особенности, что значит &v-...
ведь значение v ранее не определено.
мне кажется, что работает так, но я не уверен. если не прав, то поправьте =)
заводится новая переменная v и берется ее адрес &v. из него вычитается адрес кучи или значение стека.
но непонятно почему значение стека может бть равным нулю и почему вычитается только одно значение, а не сумма обоих?
С
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
возвращает разницу от текущего стека до последнего свободного места памяти еще не использованного функциями malloc.
полагаю более "врущая" чем freememory у Leshak . но позволяет оценить чего с памятью
Спасибо) завтра попробую сравнить результаты работы этих функций)
С кодом исправлюсь) а эта функция попалась мне где-то давно и я ее часто использую.
то, что эти переменные берутся извне - это я понимаю. а вот что делается здесь - понять пока не могу.
в особенности, что значит &v-...
ведь значение v ранее не определено.
мне кажется, что работает так, но я не уверен. если не прав, то поправьте =)
заводится новая переменная v и берется ее адрес &v.
Вы же сами и ответили. Значит важно не значение v, а где именно оно расположено в памяти. Подозерваю что и объявлена она в самом конце функции не спроста.
но непонятно почему значение стека может бть равным нулю и почему вычитается только одно значение, а не сумма обоих?
А фиг его значт что в этом __brkval на самом деле лежит. Может в разных камнях/компяляторах там все тот же адрес кучи :) Типа если он есть - ищем в одной переменной, если нет - смотрим может она по другому называется.
Не знаю, если честно - лень уже разбиратся. Я вообще с C/C++ одновременно с ардуиной началал знакомится. Мой родной - C#. А там забота о памяти - дело компилятора, а не моя :)
в особенности, что значит &v-...
ведь значение v ранее не определено.
Адрес v и есть значение стека
какое значение v принимает - по барабану
Не знаю, если честно - лень уже разбиратся. Я вообще с C/C++ одновременно с ардуиной началал знакомится. Мой родной - C#. А там забота о памяти - дело компилятора, а не моя :)
Вот я тоже на C++ одновременно с ардуиной перешел) чаще на javascript и delhpi писать приходится. дельфи - не та степь, а на джаваскрипт тоже о памяти в последнюю очередь заботишься)
но вот два килобайта в ардуине заставили заморочиться... каждый байт считать приходится...
дельфи - не та степь
Из всего выше перечисленного, помоему как раз самая близкая степь. По воспоминаниям детства (ТурбоПаскакаль 3.0 и дальше, Delphi XXX) там как раз были и указатели и освобождение/выделения памяти, и стек... но все прочно забылось за 15-ть лет :)
А вот javascript - действительно не та. Не типизированый. Интерпретируемый, а не компилируемый (хотя идет к тому), наследование - прототипное.... вообщем кроме C-подобного синтаксиса (а у кого его щас нет?) - ничего общего.
Дальше него, IMHO, будет только что-то типа Prolog (эх... как жаль что не пошел он в массы).
Вы тут хорошо во всём разобрались :)
Освобождать глобальные переменные - уже плохой стиль и самое правильное - уйти от этого. А для меня С++ самый родной, шарп не люблю. Сравнивать не будем. Каждой задаче - свой язык
Если быть "очень строгим", то "глобальные переменные" вообще зло. Засоряется namespace. Функции имеют hidden эффекты и т.п. Спасает только то, что в дуине памяти мало, нет маштабных проектов где это могло бы превратится в ад.
А для меня С++ самый родной, шарп не люблю. Сравнивать не будем. Каждой задаче - свой язык
Все верно :) Хотя есть аналоги дуины и с C# внутре :) А в будущем, подозреваю, с падением цены на мощные процы будут массово "мигать диодом на php" :) (уже пошли первые ласточки). И зубовный скрежет "старой школы" :)
Но вы правы, все зависит от задачи. Когда нужна тяжелая бизнес-логика (просто куча правил и т.п.), когда "добавить 2 гига памяти" стоит меньше чем час работы программера ищущего "где же у нас память течет" - C# рулит. А в еще более серьезных проектах даже свои еще более высокоуровненвые язычки пишутся (DSL) (и еще более прожорливые к ресурсам).
А вот когда "байты держат за горло", тут уж без C/C++ не обойтись :) Или нужен "жесткий realtime", то от C# будут только крики "дайте мне какие-нибудь костыли" :)
А про "люблю" - моя любовь дества - Prolog. Хотя в "боевой задаче" за всю жизнь всего один раз удалось уговорить его заюзать. Даже майка есть "все равно Prolog не брошу, потому что он хороший" :)
Как же хорошо, что некоторые темы не требуют отсылать к элементарным вещам, прямо отдыхаешь от "помогите новичку" :)
Хотя я тоже новичок и Leonardo мой мне нравится хотя бы тем, что заставляет лазить по даташитам, докам, инету и искать почему пины другие в сравнении с Uno и т.п. Пора открыть тему, как измерить количество гигабайт, которое я перевернул в интернете, когда искал ответ на интересующий меня вопрос :)
Всё, я в оффтоп залез :) ухожу
Кстати, только что пришла аналогия про глобальные переменные. Купил билет, пришел на сеанс, а тебя по середине сеанса выгоняют, у нас, типа, мест не хватает!!! ;) Бедные глобальные переменные!
Кстати, только что пришла аналогия про глобальные переменные. Купил билет, пришел на сеанс, а тебя по середине сеанса выгоняют, у нас, типа, мест не хватает!!! ;)
Не, это скорее уже из области многопоточности и lock-ов:
Acess denay. The process cannot access the object ... because it is being used by another process. Try again later.
Главное что-бы потом не последовало "kill process" :)
В AIX прикольно сделано, если приложение просит память а её нет, он (AIX) приложению говорит, что, типа, отстань, памяти мало. Сначала культурно говорит, потом повышая тон. Но если приложение продолжает настойчиво требовать память, это приложение просто отстреливается :) У нас так DB2 работала, потом всё дружно сдохло, сервер работал, но на пинги не отвечал, а всё из-за кривых рук, не настроили DB2.
Надо открыть пятый раздел в форуме - "Охотники на привале" :)
Всем спасибо за ответы)
сегодня, наконец, добрался до проекта. память освободил другим образом.
Оказывается, запись lcd.print("blablabla"); занимает место в оперативке. я думал, что она занимает место только в прошивке.
сократил текстовые строки и заменил одинаковые куски переменными. выиграл кучу памяти, так что удалять переменные больше не нужно)
Оказывается, запись lcd.print("blablabla"); занимает место в оперативке. я думал, что она занимает место только в прошивке.
Естественно :)
Ключевое слово PROGMEM вам поможет. Это как раз и есть указание компилятору "не нужно копировать ее в RAM" при запуске скетча (но потом нужно озаботится "чтением" когда строка понадобится). Так же слово PSTR погуглить нужно.
P.S. Если бы сразу сказали в чем именно дело :) Изначально задача была сформулированно как "_динамически_ формируем длинные строки, от которых желательно избавлятся", а не "как бы поудачней их хранить, а то памяти мало".
Сначала я хотел и с их размером разделатсья. потом понял, что мне это ничего не даст. просто стал контролировать их размер.
но места все равно было мало (строка String занимает по два байта на каждый символ). эти строки я получаю от GSM модуля и разбираю их на текст (команда) и значения (число). разбирать массив char намного сложнее.
я думал, что у меня оптимально использована память основного проекта, поэтому не заморачивался о хранении всех остальных переменных.
когда стал искать, что бы удалить, то попробовал сократить количество слов, выводящихся на экран или в ком порт. в общем сильно удивился)..
про прогмем немного знаю, но даже не думал, что мне может понадобиться переносить все слова меню в прогмем переменные...
Во! А я то думал, чего это у меня прога не пашет! PROGMEM еще и читать надо правильно!
Yes!
Понастроили тут, панимаэшь, памятей разных понавтыкали, блин! :)
Во! А я то думал, чего это у меня прога не пашет! PROGMEM еще и читать надо правильно!
Yes!
Я себе вот такую парочку накорябал:
Но, при разработке специально пишу Serial.println("BLA-BLA"); пока памяти хватает.
А как не хватает, то у меня сразу есть "кандидат для оптимизации", заменяю
Serial.println("BLA-BLA"); на println(PSTR("BLA-BLA")); и имею профит по памяти.
Так сказать искуственно создаю себе "звоночек-предупреждение".
Можно себе сделать "помогалку".
объявить два дефайна
В коде писать PRINTLN("BLA-BLA") , а потом, когда понадобится закоментить первый, раскоментить второй и будет юзатся флешь, а не RAM. Не нужно будет по всему коду лазить "переделывать".
Ну и "без фанатизма". Помним что сама ссылка на флешь, тоже память жрет. Поэтому строчки из одного-двух символов нет смысла в такую беду оборачивать. Только длинные.
Понастроили тут, панимаэшь, памятей разных понавтыкали, блин! :)
Это называется "работаем близко к железу". В этом же и прелесть дуины :)
В конце концов :
- С тех пор, - продолжал Арамис, - моя жизнь протекает очень приятно. Я начал писать поэму односложными стихами. Это довольно трудно, но главное достоинство всякой вещи состоит именно в ее трудности.
Если не согласны с ним - смотрите в сторону netduino, меги и проч. Вообщем благо прогресс вполне допускает взять более мощьное железо и не морочится оптимизацией. Более того очень часто это более выгодный путь :)
Я пока что в творческом поиске, активно изучаю/вспоминаю, объем памяти не парит. Главное сейчас научить себя и постичь тонкости, а потом всё просто, взял, да написал, что нужно. Главное не начинать с космического аппарата и довести все планы до реализации.