Memory Managerment In Objective C/ Swift
Bài đăng này đã không được cập nhật trong 3 năm
I - About
-
Application memory management is the process of allocating memory during your program’s runtime, using it, and freeing it when you are done with it.
-
In Objective-C, it can also be seen as a way of distributing ownership of limited memory resources among many pieces of data and code. When you have finished working through this guide, you will have the knowledge you need to manage your application’s memory by explicitly managing the life cycle of objects and freeing them when they are no longer needed.
-
Objective-C provides two methods of application memory management.
- manual retain-release
- Automatic Reference Counting (ARC)
-
Good Practices Prevent Memory-Related Problems
-
Freeing or overwriting data that is still in use
This causes memory corruption, and typically results in your application crashing, or worse, corrupted user data.
-
Not freeing data that is no longer in use causes memory leaks A memory leak is where allocated memory is not freed, even though it is never used again. Leaks cause your application to use ever-increasing amounts of memory, which in turn may result in poor system performance or your application being terminated.
More detail you can read here : https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html#//apple_ref/doc/uid/10000011-SW1>
This post i want to share about some topic bellows.
- Object ownership
- What is retain count?
- Property variable. Which should you for specify job
- Retain/Release /Autorelease pool and how to check object is released or not.
- ARC (Automatic Reference Counting)
- Retain cycle and how to avoid it.
- Avoid Causing Deallocation of Objects You’re Using
- How to check object used will release or not
- Tool to check memory used
-
1. Pointer Variables - Object ownership
- When a method (or function) has a local variable that points to an object, that method is said to own the object being pointed to
- When an object has an instance variable that points to another object, the object with the pointer is said to own the object being pointed to.
- The idea of object ownership is useful for determining whether an object will be destroyed so that its memory can be reused.
- An object with no owners will be destroyed. An ownerless object cannot be sent messages and is isolated and useless to the application. Keeping it around wastes precious memory. This is called a memory leak.
- An object with one or more owners will not be destroyed. If an object is destroyed but another object or method still has a pointer to it (or, more accurately, a pointer that stores the address where the object used to live), then you have a dangerous situation: sending a message via this pointer may crash your application. Destroying an object that is still needed is called premature deallocation. It is also known as a dangling pointer or a dangling reference.
a. How Objects lost owner
-
A variable that points to the object is changed to point to another object.
- (void) testPointToOtherObj{ _parentObj = [[ChangePointObj alloc] init]; _parentObj->_childObj = [[ChildObj alloc] initWithName:@"first obj"]; _parentObj->_childObj = [[ChildObj alloc] initWithName:@"second obj"]; } After testPointToOtherObj is executed the first obj will destroy because it have now owner. MemoryInvestigate[9383:138811] first obj - dealloc
-
A variable that points to the object is set to nil. With sample above. After testPointToOtherObj execute we set
_parentObj->_childObj = nil 2015-09-26 20:58:15.734 MemoryInvestigate[9491:142461] second obj - dealloc
The second child object we set to parent will also destroy
-
The owner of the object is itself destroyed.
When an object is destroyed, the objects that it owns lose an owner. In this way, one object being deallocated can cause a cascade of object deallocations.
Through its local variables, a method or a function can own objects. When the method or function is done executing and its frame is popped off the stack, the objects it owns will lose an owner.
_parentObj = nil; 2015-09-26 21:04:16.105 MemoryInvestigate[9529:144080] -[ChangePointObj dealloc] 2015-09-26 21:04:16.106 MemoryInvestigate[9529:144080] second obj - dealloc
-
An object in a collection, like an array, is removed from that collection.
There is one more important way an object can lose an owner. An object in a collection object is owned by the collection object. When you remove an object from a mutable collection object, like an instance of NSMutableArray, the removed object loses an owner.
[items removeObject:item]; // Object pointed to by item loses an owner
Keep in mind that losing an owner by any of these means does not necessarily result in the object being destroyed; if there is still another pointer to the object somewhere, then the object will continue to exist. When an object loses its last owner, the result is certain and appropriate death.
2. What is retain count?
-
retain count : It is value indicate the object has how many owner.
-
When you create or copy an object, its retain count is 1. Thereafter other objects may express an ownership interest in your object, which increments its retain count. The owners of an object may also relinquish their ownership interest in it, which decrements the retain count. When the retain count becomes zero, the object is deallocated (destroyed).
-
retainCount method of object just isn’t very useful as has been indicated The document https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/index.html#//apple_ref/occ/intfm/NSObject/retainCount
Important: This method is typically of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
Makes it pretty clear that you shouldn’t be calling retainCount, but it really doesn’t illuminate exactly how useless the method is outside of a very narrow context.
So, let us count the ways:
- The absolute retain count of an object may change at any time once an object has been passed through any system API.
- Any subclass of any system provided class counts as “through system API”; the retain count may be impacted by implementation details.
- The retain count never reflects whether an object is autoreleased.
- Autorelease is a per-thread concept whereas retain counts are global; race condition derived hilarity can easily ensue.
- The retainCount method can never return 0.
- Some classes are implemented as singletons some of the time. Some classes may internally manipulate their retain count directly (I.e. no swizzle for you!).
- While retain/release are effectively thread safe, there is always a race between calling retainCount and having the actual retain count change in some other execution context.
3. Property variable. Which should you for specify job
- An object’s properties let other objects inspect or change its state. But, in a well-designed object-oriented program, it’s not possible to directly access the internal state of an object. Instead, accessor methods (getters and setters) are used as an abstraction for interacting with the object’s underlying data.
a. Property directive
@property BOOL running;
The compiler generates a getter and a setter for the running property. The default naming convention is to use the property itself as the getter, prefix it with set for the setter, and prefix it with an underscore for the instance variable, like so:
-(BOOL)running {
return _running;
}
- (void)setRunning:(BOOL)newValue {
_running = newValue;
}
After declaring the property with the @property directive, you can call these methods as if they were included in your class’s interface and implementation files
b. The getter= and setter= Attributes
If you don’t like @property’s default naming conventions, you can change the getter/setter method names with the getter= and setter= attributes
@property (getter=isRunning) BOOL running;
The generated accessors are now called isRunning and setRunning. Note that the public property is still called running, and this is what you should use for dot-notation:
Car *honda = [[Car alloc] init];
honda.running = YES; // [honda setRunning:YES]
NSLog(@"%d", honda.running); // [honda isRunning]
NSLog(@"%d", [honda running]); // Error: method no longer exists
c. The readonly Attribute
The readonly attribute is an easy way to make a property read-only. It omits the setter method and prevents assignment via dot-notation, but the getter is unaffected.
@property (getter=isRunning, readonly) BOOL running;
Car *honda = [[Car alloc] init];
NSLog(@"Running: %d", honda.running); // ok
honda.running = NO; // Error: read-only property
d. The nonatomic Attribute
-
Atomicity has to do with how properties behave in a threaded environment. When you have more than one thread, it’s possible for the setter and the getter to be called at the same time. This means that the getter/setter can be interrupted by another operation, possibly resulting in corrupted data.
-
Atomic properties lock the underlying object to prevent this from happening, guaranteeing that the get or set operation is working with a complete value. However, it’s important to understand that this is only one aspect of thread-safety—using atomic properties does not necessarily mean that your code is thread-safe.
-
Properties declared with @property are atomic by default, and this does incur some overhead. So, if you’re not in a multi-threaded environment (or you’re implementing your own thread-safety), you’ll want to override this behavior with the nonatomic attribute, like so:
@property (nonatomic) NSString *model;
e. The strong Attribute
- The strong attribute creates an owning relationship to whatever object is assigned to the property. This is the implicit behavior for all object properties, which is a safe default because it makes sure the value exists as long as it’s assigned to the property.
f. The weak Attribute
-
Most of the time, the strong attribute is intuitively what you want for object properties. However, strong references pose a problem. For example
@class ChildObj; @interface ChangePointObj : NSObject { } @property (nonatomic, strong) ChildObj *child; @end @class ChangePointObj; @interface ChildObj : NSObject @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) ChangePointObj *paret; - (instancetype) initWithName:(NSString *)str; @end _parentObj = [[ChangePointObj alloc] init]; ChildObj *child = [[ChildObj alloc] initWithName:@"second obj"]; _parentObj.child = child; // (1) child.parent = _parentObj; //(2) _parentObj = nil; /*
(1) - parent object become owner of child object
(2) - child object become owner of perant object
(3) - we set parent to nil but bottm parent and child do not destroy.
=> This will make a retain cycle. It meam that parent, child never destroy during app running, because they are holding together.
=> to avoid retain cycle we need use weak property. Change define of child object like this.
@property (nonatomic, weak) ChangePointObj *parent;
*/
g- The copy Attribute
-
The copy attribute is an alternative to strong. Instead of taking ownership of the existing object, it creates a copy of whatever you assign to the property, then takes ownership of that. Only objects that conform to the NSCopying protocol can use this attribute.
-
Properties that represent values (opposed to connections or relationships) are good candidates for copying. For example, developers usually copy NSString properties instead of strongly reference them:
h Other Attributes The above @property attributes are all you should need for modern Objective-C applications (iOS 5+), but there are a few others that you may encounter in older libraries or documentation.
-
The retain Attribute The retain attribute is the Manual Retain Release version of strong, and it has the exact same effect: claiming ownership of assigned values. You shouldn’t use this in an Automatic Reference Counted environment.
-
The unsafe_unretained Attribute Properties with the unsafe_unretained attribute behave similar to weak properties, but they don’t automatically set their value to nil if the referenced object is destroyed. The only reason you should need to use unsafe_unretained is to make your class compatible with code that doesn’t support the weak property.
-
The assign Attribute The assign attribute doesn’t perform any kind of memory-management call when assigning a new value to the property. This is the default behavior for primitive data types, and it used to be a way to implement weak references before iOS 5. Like retain, you shouldn’t ever need to explicitly use this in modern applications.
4. Retain/Release /Autorelease pool and how to check object is released or not.
-
Before the introduction of ARC, everyone followed a ‘manual-retain-release’, or MRR, model of memory management. The basic rules are as follows:
-
You own any object you create
-
You can take ownership of an object using retain
-
When you no longer need it, you must relinquish ownership of an object you own.
-
You must not relinquish ownership of an object you do not own Under these rules, if an object is created (using a method whose name beings with “alloc”, “new”, “copy”, or “mutableCopy”), it must be relinquished when it is no longer needed. To do this you send the object a release or autorelease message. Let’s look at an example:
{ Car *aCar = [[Car alloc] init]; // ... NSString *model = aCar.model; // ... [aCar release] }
-
-
Once we’re done with the Car object, we relinquish ownership by sending a release or autorelease message. As such, relinquishing ownership of an object is typically referred to as “releasing” the object. In our example, we don’t take ownership of the string pointing to the Car model, so we don’t bother with sending it a release message.
-
Let’s look at another example of a method.
-(NSString *)model { NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@", self.carMaker, self.modelName] autorelease]; return string; }
Since we use the ‘alloc’ method to create the object, according to Rule #1, we own the string returned by alloc. It is our responsibility now, to relinquish ownership of this object before we lose reference to it. In this case, if were to relinquish it using ‘release’, the string will be deallocated before it is returned and the method would return an invalid object.
-
Finally, you can relinquish ownership of your objects by implementing the dealloc method. The NSObject class defines a dealloc method that is implemented automatically when an object has no owners. From the docs: “The role of the dealloc method is to free the object’s own memory, and to dispose of any resources it holds, including ownership of any object instance variables.”
-
In the following example, we create the instance variables carMaker and modelName. To dispose of them when we are done and free up memory, we release them in our dealloc method.
@interface Car : NSObject @property (retain) NSString *carMaker; @property (retain) NSString *modelName; @end @implementation Person // ... - (void)dealloc { [_carMaker release]; [_modelName release]; [super dealloc]; } @end
5. ARC (Automatic Reference Counting
- is a memory management enhancement where the burden of keeping track of an object's reference count is lifted from the programmer to the compiler.
- In traditional Objective-C, the programmer would send retain and release messages to objects in order to mark objects for deallocation or to prevent deallocation
- Under ARC, the compiler does this automatically by examining the source code and then adding the retain and release messages in the compiled code
1. Rules when using ARC in Objective C
The following rules are enforced by the compiler when ARC is turned on:
- You cannot call retain, release, retainCount, autorelease, or dealloc. The compiler automatically inserts the correct calls at compile time, including messaging [super dealloc] in an override of dealloc.
Code example without ARC:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Code example with ARC:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
// no need to call [super dealloc] here
}
-
You cannot cast directly between id and void *. This includes casting between Foundation objects and Core Foundation objects. You must use special casts, or calls to special functions, to tell the compiler more information about the object's lifetime.
Code example without ARC:
- (NSString *)giveMeAString { CFStringRef myString = [self someMethodThatCreatesACFString]; NSString *newString = (NSString *)myString; return [newString autorelease]; }
Code example with ARC and a cast:
- (NSString *)giveMeAString { CFStringRef myString = [self someMethodThatCreatesACFString]; // retain count is 1 NSString *newString = (__bridge_transfer NSString *)myString; // the ownership has now been transferred into ARC return newString; }
2. Converting to ARC
- Xcode 4.2 or later provides a way to convert code to ARC.
- As of Xcode 4.5, it is found by choosing Edit > Refactor > Convert to Objective-C ARC... Although Xcode will automatically convert most code, some code may have to be converted manually. Xcode will inform the developer when more complex use cases arise, such as when a variable is declared inside an autorelease pool and used outside it or when two objects need to be toll-free bridged with special casts.
3. ARC in Swift
- Swift uses ARC to manage memory. To allow the programmer to prevent strong reference cycles from occurring, Swift provides the weak and unowned keywords. Weak references must be optional variables, since they can change and become nil.
- A closure within a class can also create a strong reference cycle by capturing self references. The programmer can indicate which self references should be treated as weak or unowned using a capture list
6. Retain cycle and how to avoid it.
- As i meaing in weak property. If two objects has owner together. It called retain cycle.
- To avoid it we need change child reference to parent by property weak.
7. Avoid Causing Deallocation of Objects You’re Using
-
Cocoa’s ownership policy specifies that received objects should typically remain valid throughout the scope of the calling method. It should also be possible to return a received object from the current scope without fear of it being released. It should not matter to your application that the getter method of an object returns a cached instance variable or a computed value. What matters is that the object remains valid for the time you need it.
-
There are occasional exceptions to this rule, primarily falling into one of two categories
-
When an object is removed from one of the fundamental collection classes.
heisenObject = [array objectAtIndex:n]; [array removeObjectAtIndex:n]; // heisenObject could now be invalid.
When an object is removed from one of the fundamental collection classes, it is sent a release (rather than autorelease) message. If the collection was the only owner of the removed object, the removed object (heisenObject in the example ) is then immediately deallocated.
-
When a “parent object” is deallocated.
id parent = <#create a parent object#>; // ... heisenObject = [parent child] ; [parent release]; // Or, for example: self.parent = nil; // heisenObject could now be invalid.
In some situations you retrieve an object from another object, and then directly or indirectly release the parent object. If releasing the parent causes it to be deallocated, and the parent was the only owner of the child, then the child (heisenObject in the example) will be deallocated at the same time (assuming that it is sent a release rather than an autorelease message in the parent’s dealloc method).
-
** 8. How to check object used will release or not**
- We can implement function dealloc in objective c, deinit in swift to determind it is release or not. If dealloc/deinit called it mean that object release.
9. Tool to check memory used
In xcode go to "open develop tool -> instrument". We will see like this : ![developTool.png]
I usually use 2 tool to check memory issue a. Leaks : There’s one great automated tool to help you check your app for leaks. I will have other post to guide about this tool b. Time profile :
- Lots of developers start out with a vague idea that their app should go fast – and it’s a worthy aim. Then they read about something called “premature optimisation” and wonder how this terrible thing that the greybeard programmers frown at might be avoided. In the worst case, the novice developers forget about optimisation altogether!. This tool will help you.
All rights reserved