`
cenphoenix
  • 浏览: 160575 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Memory Management

阅读更多

First off, it’s worthing clarifying that much of what is covered here is as much Cocoa as it is Objective-C. However, since the two are quite closely tied when it comes to developing Mac/iPhone applications, I’ve decided to keep with the Objective-C theme as it relates to the title of this and subsequent posts.

This post will review some of the nuances of memory management. I won’t go into all the details of memory management (see Objective-C Programming Guide , Cocoa Fundamentals and Memory Management Programming Guide for Cocoa ), rather, I’ll point out some of the more subtle concepts to keep in mind as you begin to work with objects.

Object Ownership

Rule #1 – If you create an object using alloc, new or a variant of copy (e.g. mutableCopy), you need to free (release or autorelease) that object. This also applies if you send a retain message to an object.
Rule #2 – If you didn’t create an object directly, don’t attempt to release the memory for the object.

For instance, here is an object that I “own” given that I’ve called ‘alloc’ to create the object. It’s up to me to release the memory for this object:

1
2
3
4
5
  TestClass *ptr = [[TestClass alloc] init];
 
  ...
 
  [ptr release];

Let’s look at two examples where we are not responsible for managing the memory associated with an object. First, when using a factory (aka convenience) methods of a class. For instance:

1
2
3
NSString *str;
str = [NSString stringWithFormat:@"Some string here..."];
NSLog(str);

The second example, is if you call an accessor method that returns an object. Assume that the object TestClass below has a getter method that returns a pointer to an instance variable named firstName that is an NSString.

1
2
3
  NSString *str;
  // No need to release this object
  str = [TestClass firstName];

This makes sense if you think about it. The getter simple returns a reference (pointer) to an existing object. Now, if you want to retain (express an interest in the object to keep it around) then you would need to use ‘retain’ to bump the reference count. However, if we simply want a pointer to the object as shown here, we don’t have responsibility to release the object.

Initializing Objects

The order of things happening when initializing an object is of great relevance. For example, look at this block of code:

1
2
3
4
5
6
  TestClass *ptr = [TestClass alloc];
  [ptr init]
 
  // Do something with the object
  if (ptr)
    ...

Seems harmless enough, right? Allocate an object and send a message to initialize the object. Here’s the problem, if the init method returns nil (which all good initializers do upon failure to properly initialize an object), the code on line 5 would pass the test (that is, ptr would not be nil).

Now compare that with this approach:

1
2
3
4
5
  TestClass *ptr = [[TestClass alloc] init];
 
  // Do something with the object
  if (ptr)
    ...

In the code above, assuming the init method returns nil upon failure, ptr will be set to nil, and the code on line 4 would not pass the test. Much better.

So, the lesson here is twofold: always return nil from an initializer method when the method fails to properly initialize the object. Second, it’s a good practice to combine a call to alloc and init into one step. We’ll talk more about initializers in a separate post.

Releasing Objects

Let’s talk about the other end, releasing objects. Have a look at the implementation for a simple class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#import "TestClass.h"
 
// ================================
// = Implementation for TestClass =
// ================================
@implementation TestClass
 
-(NSString *) str
{
  return str;
}   
 
 
-(void) setStr:(NSString *)input
{
  [input retain];
  [str release];
  str = input;
}
 
-(void) dealloc
{
  [str release];
  [super dealloc];
}
 
@end

Look at the code below that creates an instance of the TestClass, calls the setter method to initialize the ’str’ instance variable, and releases the memory for the ‘ptr’ object.

1
2
3
4
5
6
7
8
9
10
11
12
13
#import "TestClass.h"
 
int main(int argc, const char * argv[])
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
  TestClass *ptr = [[TestClass alloc] init];
  [ptr setStr:@"Fubar"];
 
  [ptr release];
  [pool drain];
  return 0;
}

The dealloc method in TestClass releases the memory for the ’str’ instance variable, and it seems all is well. However, if at some point, somewhere inside the class implementation an attempt was made to check if the ’str’ instance variable is nil (prior to doing some operation) for example:

1
2
3
4
if (str)
  do something...
else
  do something else...

the if statement would pass and the code on line 2 would be run. Not a good thing.

An alternative is to replace the call to release with a call to the setter method and pass in nil . Look at the dealloc method below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-(void) setStr:(NSString *)input
{
  [input retain];
  [str release];
  str = input;
}
 
...
 
-(void) dealloc
{
  [self setStr:nil];
  [super dealloc];
}

The reason this works is that you can send a message to a nil object without raising an exception. If you follow the trail you’ll see inside the setStr method that the variable ‘input’ (which is nil) is sent a message to retain . This is effectively ignored, as the object is nil . The next line releases the string ’str’. The last line sets ’str’ to the value of the input parameter (which is nil ). This prevents the problem in the previous example where ’str’ still had a reference to a location in memory (even though the memory had been released).

As I was getting familiar with this, I wrote a short example in Xcode. Here is the test block for the dealloc method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-(void) dealloc
{
  NSLog(@"Address of 'str' before release is: %ld", str);
 
  // After this, 'str' still points to a memory location
  [str release];
 
  // After this, 'str' will be nil  (** This is the preferred approach **)
  //[self setStr:nil];
 
  NSLog(@"Address of 'str' is after release is: %ld", str);
 
  // Notice the result of this based on how the instance var 'str' is released (above)
  if (str != nil)
    printf("'str' still points to a memory location (after being released)!");
  else
    printf("'str' now points to nil.");        
 
	[super dealloc];
}

Notice in this case that line 6 uses release. See the output below:

Now, if you comment out line 6 and remove the comment from line 9, you’ll get the following output. Notice how the reference to ’str’ after is 0 (nil).

You can download the Xcode project here if you’d like to take a closer look at the complete example. Hopefully this information will save you some time trying to track down an elusive memory leak.

分享到:
评论

相关推荐

    memory management

    memory management 动态内存分配 FIFO算法

    Pro .NET Memory Management

    《Pro .NET Memory Management》这本书由Konrad Kokosa撰写,旨在帮助开发者更好地理解.NET内存管理的内部机制,从而提高代码质量、性能和可扩展性。 #### 二、.NET内存管理概述 .NET内存管理主要涉及两个方面:...

    Virtual memory management ppt

    在“Virtual memory management ppt”中,主要探讨了虚拟内存管理的多个关键概念和策略。 11.1 引言:这部分介绍了虚拟内存管理的基本原理,包括替换策略和获取策略。替换策略是当内存满时,系统用来选择哪些页面...

    Aarch64 Kernel Memory Management.pptx

    aarch64 Linux Kernel Memory Management, aarch64 Linux Kernel Memory Management, aarch64 Linux Kernel Memory Management

    Memory Management: Algorithms and Implementation in C_C++

    本资源“Memory Management: Algorithms and Implementation in C_C++”聚焦于这一主题,旨在深入探讨如何有效地管理和分配内存,以及在C和C++中实现这些算法。 内存管理主要涉及以下几个关键知识点: 1. **动态...

    C_C++ 内存管理算法和实现 Memory Management Algorithms and Implementation in C_C++

    C_C++ 内存管理算法和实现 Memory Management Algorithms and Implementation in C_C++ C_C++ 内存管理算法和实现 Memory Management Algorithms and Implementation in C_C++ C_C++ 内存管理算法和实现 ...

    Pro Multithreading and Memory Management for iOS and OS X with ARC

    Pro Multithreading and Memory Management for iOS and OS X with ARC, Grand Central Dispatch epub

    Memory Management Simulator

    "Memory Management Simulator" 是一个模拟器,用于帮助理解并可视化内存管理的过程。这个模拟器利用了Java Swing库来构建用户界面,使得用户能够交互地探索内存分配和回收的机制。 在Java中,内存分为堆(Heap)和...

    sdk2003文档 Memory Management

    sdk2003 win32 Memory Management sdk2003 win32 Memory Management

    翻译《Memory Management in the Java HotSpot™ Virtual Machine》

    《Memory Management in the Java HotSpot™ Virtual Machine》一文深入探讨了Java HotSpot虚拟机中的内存管理机制,这是Java性能优化的关键领域。HotSpot虚拟机是Oracle JDK和JRE的一部分,以其高性能和优化能力而...

    《MIT JOS Lab2: Memory Management》实验代码

    MIT JOS Lab2: Memory Management,上海交通大学最新版本的JOS Lab2完整版代码,80分测试满分 详细解析地址:https://blog.csdn.net/qq_32473685/article/details/99625128

    Objective C Memory Management Essentials(PACKT,2015)

    Objective-C Memory Management Essentials will familiarize you with the basic principles of Objective-C memory management, to create robust and effective iOS applications. You will begin with a basic ...

    Memory Management: Algorithms and Implementation in C/C++

    C/C++实现的内存管理算法教材,CHM格式

    Objective C Memory Management Essentials

    this book will help you become aware of memory management and how to implement this correctly and effectively while being aware of the benefits at the same time. This tutorial-based book will actively...

    C++ Memory Management Innovation

    ### C++内存管理创新:GC Allocator #### 引言 在C++编程中,内存管理一直是一个关键且复杂的任务。大多数C++程序员不得不手动管理内存,包括分配和释放内存资源,这不仅耗时而且容易出错。随着软件工程的发展,...

    Effective Memory Management.rar

    本资料"Effective Memory Management"深入探讨了内存管理的核心概念、策略和技术。 首先,内存管理的基本概念包括静态内存分配与动态内存分配。静态内存分配通常在编译时完成,如栈内存,其大小和生命周期在编译时...

    Oracle Memory Management and HugePage

    Oracle发展这么多年,提供了多种的内存管理方式,从最早SGA、PGA手工管理,到9I版本出现的PGA的自动管理,到10G版本出现的SGA自动管理(ASMM),再到11G版本出现的memory自动管理(AMM),Oracle基本是在朝着智能化、...

    Win8.1蓝屏提示错误Memory Management并重启怎么办.docx

    Windows 8.1 蓝屏错误解决方法 - Memory Management 并重启解决方案 Windows 8.1 蓝屏错误是一个常见的问题,特别是当系统遇到内存管理问题时。这种情况下,系统将出现蓝屏并自动重启,影响用户的工作和娱乐体验。...

Global site tag (gtag.js) - Google Analytics