If you're new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for visiting!

Call the plumber, it's-a-leaking!

Update 4/12/13: These days, you should probably be using Apple’s new Automatic Reference Counting (ARC) technology instead of doing manual memory management. For more details on ARC, check out our ARC tutorial. We also have an updated Instruments tutorial you might want to check out.

This is the second article in a three-part series on working with memory in Objective-C on the iPhone. In the first part of the series, we covered how to manage memory in Objective-C by using instance variables and reference counting.

No matter how well you understand memory management in Objective-C, from time to time you’re bound to make mistakes. But often there’s way too much code to search line-by-line for problems (unless you want your hair to turn gray!)

Luckily, Apple has provided some great ways to help you find memory-related problems in your applications. Sometimes these tools scare new developers, but they’re actually pretty awesome and easy to use!

That’s what this Instruments tutorial is all about. You’ll get hands hands-on experience using XCode and Instruments to debug and detect memory related problems.

This Instruments tutorial assumes you are familiar with memory management in Objective-C. If you are still shaky on the subject, you may wish to read the memory management tutorial first.

Getting Started

Our goal in this Instruments tutorial is to check for and resolve any memory leaks in an example app that illustrates common memory-related mistakes. So to get started, download a leaky app that I’ve put together for this Instruments tutorial.

Open up the app and run it in XCode. You’ll see a list of sushi in a table view. Try selecting several rows, and then – BOOM! You get the dreaded EXC_BAD_ACCESS error, and the debugger is no help:

This can be very frustrating to many beginning developers, as it’s not clear where the problem is. Here’s the advice I generally give to developers when you hit an EXC_BAD_ACCESS error:

  1. Set the NSZombieEnabled argument in your executable options, which sometimes helps narrow down the cause
  2. Run with Apple Instruments such as Leaks to look for memory issues
  3. Set a breakpoint in your code and step through until you narrow down where it’s crashing
  4. Tried and true “comment out code till it works” then backtrack from there :]

So let’s try this out for ourselves by trying option #1 – turning on NSZombieEnabled.

Zombie Invasion!

Unfortunately, the NSZombieEnabled option has nothing to do with the zombie apocalypse, so you can put away your boomsticks and chainsaws :]

Sorry, it's not those kind of zombies! Image credit: werewolf from sxc.hu.

NSZombieEnabled is a flag that you can enable that will provide a warning when you try to access an object that has been deallocated. And since accessing deallocated memory is one of the most common reasons for crashing, this is a good thing to try first.

To set this up, expand the Executables group in your sidebar in XCode, and double click the PropMemFun executable. Select the Arguments tab, go to the “Variables to be set in the environment” section, and click the Plus button. Set the name of the variable to NSZombieEnabled, and set the value to YES, as follows:

Now run the app, and click on a few rows again until it crashes. Go to your console log, and you’ll see the following message:

2011-02-03 12:07:44.778 PropMemFun[27224:207] ***
-[CFString respondsToSelector:]: message sent to deallocated instance ...

The program will also halt on the exact line where it’s crashing now. You can go up the backtrace to find the exact line where it’s crashing by selecting the first area in the backtrace that is your code – in this case tableView:didSelectRowAtIndexPath.

Aha! Now you know that in this line, a message is being sent to a deallocated string. This line uses two strings: _lastSushiSelected, and sushiString.

Well sushiString looks OK, because it’s initialized with stringWithFormat (which returns an autorelease variable), so it should be safe to use until the next run loop. But what about _lastSushiSelected?

_lastSushiSelected was set the last time this method was run to sushiString. But sushiString is an autorelease variable, so at some point it will be released, and the memory will be deallocated. But then _lastSushiSelected would still be pointing to deallocated memory! Which explains the problem – sending a message to deallocated memory causes a crash.

So to solve this, we just need to retain _lastSushiSelected so that the memory doesn’t go away. So replace the last line with the following:

_lastSushiSelected = [sushiString retain];

Compile and run your code, and now you should be able to run without crashing!

Build, Analyze, and Recognize

Ok, so we have an app that isn’t crashing – a good first step. But next, we need to start making sure that it isn’t leaking any memory.

There’s an easy way to perform an initial first-glance check on your app to see if it has any memory leaks or other problems – use the built-in Build and Analyze function.

This will make XCode run through your code and look for any mistakes it can automatically detect, and warn you about any potential problems. It doesn’t catch everything, but when it does catch things it’s a really quick and easy way to find out about the problems.

Give it a shot by selecting Build\Build and Analyze. You should see that it detected a memory leak, as you can see below:

The message says that there’s a potential leak related to the “alertView”. If you look at this line, you’ll see that the UIAlertView was created with a alloc/init (which returns an object with a reference count of 1), but never released! There are several ways to fix this, but one way is to add the following after [alertView show]:

[alertView release];

Go to Build\Build and Analyze again, and you’ll see that there are no remaining issues.

Leaks and Plumbers

Unfortunately, you can’t rely on Build\Build and Analyze to catch everything. There’s one other great automated tool to help you check your app for leaks – the Leaks Instrument.

Let’s try it out. Go to Run\Run with Performance Tool\Leaks, and select a few rows in the table view. Also scroll up and down the table view from the top of the table to the bottom of the table. After bait of experimentation, you should start seeing some leaks popping up in the Leaks tab, which show up as blue bars.

Click the stop button, then go to the toolbar in the middle and click it to change from “Leaked Blocks” to “Call Tree”. In the panel in the lower left, click “Invert Call Tree”, and “Hide System Libraries”. You’ll see that it found two different methods in the code with memory leaks, as you can see below:

If you double click a function name, it will take you directly to the line of code that creates the object that was leaked. This should give you a really good hint where the problem lies, and if you examine the code and think about it a bit, you should be able to figure out what the problem is and fix it.

So why not take a look at the code and see if you can figure out what the problem is and fix it? Once you’ve made a fix, you can run Leaks again and verify that the leak no longer occurs. Come back here once you’ve finished, or gotten stuck!


…waiting…

…waiitng…

…waiting…

Tomato-San is angry!

What?! Are you still reading here?! You can do it – go ahead and try! :]

The Solution

tableView:didSelectRowAtIndexPath

Leaks tells us that the string created and stored into sushiString is leaked. So let’s think through why this is, step by step:

  1. When sushiString is created, it’s created with stringWithFormat. This returns an object with a retain count of 1, and a pending autorelease.
  2. In the last line in the method, you call retain on the sushiString (bumping the retain count up to 2) and store it into _lastSushiSelected.
  3. Later on, the autorelease takes effect, decrementing the retain count to 1.
  4. Next time the tableView:didSelectRowAtIndexPath method is called, you override the _lastSushiSelected variable with a pointer to a new string – without releasing the old one! So that old string still has a retain count of 1, and is never released.

One solution to this is to add the following line before setting lastSushiSelected to the sushiString:

[_lastSushiSelected release];

tableView:cellForRowAtIndexPath

Just like in the previous method, a string that’s created and stored into a variable named sushiString is leaked. Here’s what’s going on:

  1. A new string is created with alloc/init.
  2. This returns an object with a reference count of 1.
  3. However, this reference count is never decremented, so there’s a memory leak!

This could be solved in one of three ways:

  1. Call release on sushiString after setting the textLabel to the string.
  2. Call autorelease on sushiString after creating it with alloc/init.
  3. Instead of using alloc/init, use stringWithFormat, which returns a string already marked as autorelease.

Plumb the Leaks!

Fix the above two problems, compile and run Leaks again, and verify that you no longer have any leaks in the app!

Where To Go From Here?

Here is a sample project with the updated app, with no leaks or crashes.

At this point, you should have some good hands-on experience with how to find memory leaks in your app using NSZombieEnabled, Build and Analyze, and the Leaks Instrument. You should be able to apply these techniques to your projects to help find and resolve memory leaks!

Next check out the third article in this series, where I cover how to check your apps for memory leaks or memory-related mistakes, via using Instruments and other helpers.

If you have any other advice or tips to developers for good techniques to find memory leaks in your apps, please add your thoughts in the comments below!

from:http://www.raywenderlich.com/2696/instruments-tutorial-for-ios-how-to-debug-memory-leaks

Instruments Tutorial for iOS: How To Debug Memory Leaks【转】的更多相关文章

  1. Instruments Tutorial for iOS: How To Debug Memory Leaks

    http://www.raywenderlich.com/2696/instruments-tutorial-for-ios-how-to-debug-memory-leaks Update 4/12 ...

  2. [Angular2 Router] Exiting an Angular 2 Route - How To Prevent Memory Leaks

    In this tutorial we are going to learn how we can accidentally creating memory leaks in our applicat ...

  3. The Introduction of Java Memory Leaks

    One of the most significant advantages of Java is its memory management. You simply create objects a ...

  4. 【转】简单内存泄漏检测方法 解决 Detected memory leaks! 问题

    我的环境是: XP SP2 . VS2003 最近在一个项目中,程序退出后都出现内存泄漏: Detected memory leaks! Dumping objects -> {98500} n ...

  5. On Memory Leaks in Java and in Android.

    from:http://chaosinmotion.com/blog/?p=696 Just because it's a garbage collected language doesn't mea ...

  6. _CrtSetBreakAlloc简单内存泄漏检测方法,解决Detected memory leaks!问题

    我的环境是: XP SP2 . VS2003 最近在一个项目中,程序退出后都出现内存泄漏: Detected memory leaks! Dumping objects -> {98500} n ...

  7. Diagnosing out of memory errors and memory leaks 内存泄露实例 C Java JavaScript 内存泄露

    小结: 1. 数据库连接池. JDBC语句和结果对象必须显式地关闭. 2. 电梯到目标楼层后地址是否被释放 When a button is pressed: Get some memory, whi ...

  8. 【Visual Studio】简单内存泄漏检测方法 解决 Detected memory leaks! 问题(转)

    原文转自 http://blog.csdn.net/u011430225/article/details/47840647 我的环境是: XP SP2.VS2003 最近在一个项目中, 程序退出后都出 ...

  9. Identify Memory Leaks in Visual CPP Applications —— VLD内存泄漏检测工具

    原文地址:http://www.codeproject.com/Articles/1045847/Identify-Memory-Leaks-in-Visual-CPP-Applications 基于 ...

随机推荐

  1. (转)【Android】获取Mac地址【2】

    [Android]获取Mac地址[2] 之前写了[Android]获取Mac地址[1]有些不够详细,现在贴上一些其他代码,仅供参考. (1) 调用android 的API: NetworkInterf ...

  2. EasyWeChat微信开放平台第三方平台接入

    EasyWeChat微信开放平台第三方平台接入 https://www.cnblogs.com/bainiu/p/8022729.html

  3. GOF23设计模式之单例模式(singleton)

    一.单例模式概述 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点. 由于单例模式只生成一个实例,减少了系统性能开销.所以当一个对象的产生需要比较多的资源时,如读取配置.产生其他依赖对象时, ...

  4. (转)pipe row的用法, Oracle split 函数写法.

    本文转载自:http://www.cnblogs.com/newsea/archive/2010/12/14/1905482.html 关于 pipe row的用法2009/12/30 14:53 = ...

  5. java从键盘输入一组数据,输出其最大值,平均值,最小值没法输出

    总结::需要耐心,加思考.做事不思考,那就是白做徒劳!!!!! package com.aini; import java.util.Scanner; //操...为什么数组的大小比较我硬是搞不懂,比 ...

  6. AngularJS:template

    ylbtech-AngularJS: 1.返回顶部 1.   2. 2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部   9 ...

  7. python开发进程:共享数据&进程池

    一,共享数据 展望未来,基于消息传递的并发编程是大势所趋 即便是使用线程,推荐做法也是将程序设计为大量独立的线程集合 通过消息队列交换数据.这样极大地减少了对使用锁定和其他同步手段的需求, 还可以扩展 ...

  8. DOM对象与JQuery对象

    在初学JAVA时,经常会迷惑,分不清DOM/JQuery对象,以及可以调用的方法. 1.什么是DOM/JQuery对象 DOM对象,即是我们用传统的方法(javascript)获得的对象: eg:va ...

  9. Pandas:表计算与数据分析

    目录 Pandas之Series Pandas之DataFrame 一.pandas简单介绍 1.pandas是一个强大的Python数据分析的工具包.2.pandas是基于NumPy构建的. 3.p ...

  10. cuteFTP连接不上VM虚拟机中RedHat&…

    摸索了一下午,终于解决了问题:主要原因是因为redhat系统配置文件默认root用户无法使用ftp,只需作如下修改就可以使用了.            1.找到/etc/vsftpd/目录修改下面的连 ...