Показаны сообщения с ярлыком Memory leaks. Показать все сообщения
Показаны сообщения с ярлыком Memory leaks. Показать все сообщения

четверг, 1 октября 2009 г.

Борьба с утечками памяти

Наверное 90% крэшей приложения связанно с некоректной работой с памятью. Иногда, в большом проэкте, чтоб отловить такой крэш может затратиться значительное время. И хорошо, когда по внешним признакам падения приложения(то есть на каком экране или при каких действия пользователя) можно определить из за чего именно оно упало. Но к сожалению не всегда так. Какие же первые меры необходимо принять, после крэша? На мой взгляд самое логичное и простое – это посмотреть, что вывелось в консоль дебагера. Чаще всего в консоли можно увидеть такое сообщение:

Первая фраза, из сообщения:
-[NewObject show]: unrecognized selector sent to instance 0x12179b0
указывает на то, что у объекта NewObject был вызван не существующий метод show. Здесь, все просто – возможны 2 варианта:
  • вы просто ошиблись с именем метода или со списком передваемых параметров;
  • NewObject не NewObject, а что то другое. Такой вариант возможен, когда вы используете авторелизные объекты. Вы посылаете сообщение объекту, который был уже освобожден и в итоге в переменной хранятся некоректные данные (к примеру указатель на другой объект). Так что вам предстоит кропотливый поиск освобожденного объекта.
Но за частую консоль не предоставляет никакой отладочной информации. Для такого случая в Xcode предоставляется средство позволяющее ускорить процесс поиска освобожденного объекта. Для активации этого средства необходимо прописать переменную окружения NSZombieEnabled и установить ее значение в YES. Для этого в группе Executables вызовте свойства для вашего executable: В появившемся окне перейдите на вкладку Arguments добавте перменную окружения NSZombieEnabled и установите ее значение YES. В итоге у вас должно быть нечто вроде этого: Теперь можете опять попробовать запустить приложение. В этом случае сообщение будет посодержательней: Ну а далее – знание проекта и ваша интуиция... Эти способы хорошо применять на часто повторяющихся крэшах, которые удается воспроизвести при определенных действиях. Но иногда возникает такое ощущние, что программа начала жить своей жизнью. То работает, работает при определенных действиях, а потом ни с того ни с его падает. В такой ситуации следует вводить “тяжелую артилерию”. Под тяжелой артилерией я понимаю интсрумент Leaks и статический анализатор кода, о котором я расскажу в следующей статье. Leaks – утилита, которая в реалтайме анализирует выделяемую и освобождаемую память и на основе полученных данных отображает объекты, которые утекают. Для того, чтоб запустить Leaks, выберете в меню Run – Start with Performance Tools – Leaks. Приложение установится в телефон/симулятор и запустится на выполнение. При этом у вас появится окно инструмента Leaks: Верхняя часть, ObjectAlloc, говорит нам о размере потребляемой памяти приложением. Нижняя часть – утечки памяти в прогамме. Если Leaks обнаруживает лики, они сразу же отобажаются в виде оранжевых пик и в виде записи процент – размер – адрес – объект. Более детальную ифнормацию вы можете посмотртеть в строке адреса, нажав на кружочек со стрелочкой: В появившемся окне наибольший инетерес вызывает столбец Responsible Caller, в который заносится метод и имя класса, у которого был вызван метод, произвевший утечку памяти. Остается только найти этот метод и исправить утекаемый объект.

четверг, 3 сентября 2009 г.

iPhone static library

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

В мире *nix систем да и вообще в мире OC существует 2 вида библиотек.

  1. динамические;
  2. статические.

Каждый тип библиотек имеет свои достоинства и не достатки. Прозрачный механизм создания динамических библиотек под iPhone отсутствует, хотя лично мое мнение – я не вижу большого смысла в использовании их под iPhon'ом. Нам же, наибольший интерес, представляют статические библиотеки, речь о которых пойдет далее в статье.

Статическая библиотека – это хороший способ повтороного использования кода. Кроме того, в некоторых проектах, при использовании множества не маленьких OpenSource – решений применение статических библиотек – отличный вариант сократить время на перекомпиляцию проекта. Это достигается путем хранения заранее обработанного компилятором исходного кода в объектные файлы.

В nix системах, как правило, статические библиотеки имеют расширение *.a. Таким образом, статическая библиотека – это архив, содержащий в себе объектные файлы.

То что это архив, а не, скажем, цельный бинарник, вы можете убедиться путем разархивации его. Для этого вам необходимо в терминале выполнить комнаду:

ar -xимя_статической_библиотеки

В результатет, в том же каталоге, у вас должны появиться распакованные объектные файлы.

Итак, перейдем к практике. Практиковаться мы будем, на свежесозданном проекте и исходниках обертки над sqlite – FMDatabase.

  1. Для этого создадим новый проект, к примеру Window-based Application, (тип проекта может быть любой) и назовем его MakeStaticLib. Далее, для удобства, создадим новую группу для обертки, привяжем ее к папке и добавим в нее исходники.
  2. Нажмем правой кнопкой, на группу Classes и выберем пункт AddNew group. Свежесозданную группу назовем FMDatabase и создадим для нее одноименную папку. Для этого зайдем в свойства группы FMDatabase, нажмем на кнопку Choose и выберем папку, где мы хотим хранить исходники.
  3. Добавим исходники FMDatabase в проект, (взять их можно с сайта http://code.google.com/p/flycode/)
  4. На этом подготовительная часть окончена, теперь приступим непосредственно к созданию библиотеки. Для этого нажмем правой кнопокй на раздел Targets и выберем пункт AddNew Target.
  5. В появившемся окне выберем тип target'а Static Library, назовем ее FMDatabase и нажмем Finish. В результате структура проекта должна получиться следующая:
  6. Теперь приступим непосредственно к добавлению исходников к статической библиотеки. Здесь прячется небольшая хитрость. Дело в том, что при добавлении исходников в проект, по умолчанию они добавляются в главный таргет, а он у нас является MakeStaticLib. На простороах сети, в основном, я встречал способ, при котром файлы добавлялись напрямую в Static lib target, но к сожалению с первого раза я не смог повторить этот трюк и нашел другой, на мой взгляд, более красивый способ. Для этого выберем ТОЛЬКО *.m файлы, которые мы хотим, чтоб присутствовали в библиотеке, выбрем у них пункт Get Info, перейдем на вкладку Targets и сменим “пункт назначения” c MakeStaticLib на FMDatabase:
  7. Далее добавим библиотеку в наш проект. Для этого мы зайдем в свойства таргета MakeStaticLib на вкладку General, и выберем один из 2х способов. Первый способ заключается в том, что мы добавим библиотеку как Direct dependencies объект. Это дает возможность, после изменения кода библиотеки, автоматически перекомпилировать статическую библиотеку во перекомпиляции всего проекта. Иначе, если вы вебрете второй способ, добавления библиотеки как Linked Libriries объект, вам будет необходим сперва перекомпилировать библиотеку вручную, а потом сам проект. На мой взгял это не совсем удобно и я бы вам порекомендовал добавлять как Direct dependencies объект.
  8. И наконец последний пункт, который многие не понимают зачем делать, так как и без него все работает. Для того, чтобы в библиотеки нормально отрабатывали возможности языка Objective C (к примеру категории) необходимо добаить флаг -ObjC к флгам линковщика (Other linker flags). Делается это в Info таргета MakeStaticLib, на вкладке Build в секции Linking.

На этом создание статической библиотеки окончено.