Memory issues to be aware of under arc

Source: Internet
Author: User

Before sending an article about picture loading optimization, or caused a lot of attention, but there are a lot of people do not understand the feedback, this talk about the iOS in some of the use of Arc notes, I believe that the development of iOS will not be unfamiliar to arc.
This is not about the use of Arc, just to introduce the next arc can still occur under the memory leak problem, may not be complete, welcome to add.

Ps: About the use of Arc and memory management issues, it is strongly recommended to look at the official documentation, the memory management of the principle of a very detailed introduction, I believe that the MRC has seen this.

There is also a simple and practical arc Tutorial: ARC Best Practices

In the 2011 WWDC, Apple mentioned that 90% of the crash were caused by memory management, and ARC ( Automatic Reference Counting ) was the solution given by Apple. With ARC enabled, developers do not need to worry about memory management, and the compiler will handle it for you (note that arc is a compiler feature, not an iOS runtime feature, not a garbage collector in other languages).
Simply put, the compiler will automatically generate the reference count code for the instance when compiling the code, helping us to complete the work that the MRC needs to do before, although it is said that the compiler will perform some optimizations.

Although arc can solve most of the memory leaks, there are still some places we need to be aware of.

Circular references

循环引用简单来说就是两个对象相互强引用了对方, that retain the other side, which leads to the memory leaks that no one can release. For example, when declaring a delegate, you generally use weak instead of retain or strong, because once you do that, it is very likely to cause a circular reference.

This simple circular reference as long as in the process of coding more attention, generally can be found.
The solution is also very simple, usually a strong reference in the loop chain is changed to a weak reference can be resolved.
Another block-induced circular reference problem is often a problem that developers who are unfamiliar with the block principle are less likely to discover.

Circular reference caused by block

Let's take a look at the official documentation. Explanation of block invocation: Object and Block Variables

When a block was copied, it creates strong references to object variables used within the block. If you use a block within the implementation of a method:

  1. If You access an instance variable by reference, a strong reference are made to self;
  2. If You access an instance variable by value, a strong reference are made to the variable.

There are two main rules:
第一条规则,如果在block中访问了属性,那么block就会retain住self。
第二条规则,如果在block中访问了一个局部变量,那么block就会对该变量有一个强引用,即retain该局部变量。

According to these two rules, we can know the situation where the circular reference occurred:

//规则1self.myblock = ^{    [self doSomething];           // 访问成员方法 NSLog(@"%@", weakSelf.str); // 访问属性};//规则2ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];[request setCompletionBlock:^{ NSString* string = [request responseString];}];

Object has a strong reference to the block, and inside the block there is a strong reference to the external object, which forms a closed loop and a memory leak occurs.

How to solve this kind of memory leak?
You can use the block variable to solve it, first, or to see what the official documents say:
Use Lifetime Qualifiers to Avoid strong Reference Cycles

In manual reference counting mode, with the effect of not __block id x retaining x. In ARC mode, the __block id x defaults to retaining X (just as all other values). To get the manual reference counting mode behavior under ARC, your could use __unsafe_unretained __block id x ;. As the name __unsafe_unretained implies, however, having a non-retained variable are dangerous (because it can dangle) and is therefore D Iscouraged. Better options __weak is to either use (if you don't need to support IOS 4 or OS X v10.6), or set the __block value to n Il to break the retain cycle.

The official website offers several options, let's take a look at the first, with the __block variable:

在MRC中,__block id x不会retain住x;但是在ARC中,默认是retain住x的,我们需要
使用__unsafe_unretained __block id x来达到弱引用的效果。

Then the solution is as follows:

id weakSelf = self;  //MRC//__unsafe_unretained __block id weakSelf = self;   ARC下面用这个self.myblock = ^{ [weakSelf doSomething]; NSLog(@"%@", weakSelf.str); };

<!--# # performselector problem [self performselector: @selector (foo:) WithObject:self.property Afterdelay:3]; The principle of the Performselector delay call is such that the system will automatically add the Self.property ' Retaincount ' to the above function until selector execution is complete before the Self.property ' Retaincount ' minus 1. This way, if selector has not been executed, self will not be able to be released, and it may be a memory leak. The better solution is to cancel out the perform: [NSObject cancelpreviousperformrequestswithtarget:self]; Leaks due to this cause do not violate any of the rules and are intrument to be discovered. -

Nstimer's Problem

We all know that a timer is used to execute one or more of the methods we specify at some point in the future, and then the problem comes (not the excavator, of course). How does the system ensure that the timer triggers the action when the method we specify is valid? What if receiver's not working?

答案很简单,系统会自动retain住其接收者,直到其执行我们指定的方法。

Take a look at the official documentation and suggest you write a demo test yourself.

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats
target the object to which to send the message specified by aselector when the timer fires. The timer maintains a strong reference to target until It (the timer) is invalidated. (The system maintains a strong reference until the timer calls invalidated) userInfo the user info for the timer. The timer maintains a strong reference to this object until It (the Timer) is invalidated. This parameter may nil.repeats If YES, the timer would repeatedly reschedule itself until INV Alidated. If NO, the timer is invalidated after it fires.          

It can be noted that the timer of a one-time repeats (repeats is no) will automatically call invalidated after it is triggered, and the repetitive timer will not.
Now that's the problem again, take a look at the following code:

- (void)dealloc{    [timer invalidate];    [super dealloc];}

This is a very easy mistake, if the timer is a repetitive timer, then the self object will be a timer to retain live, this time do not call invalidate , the self object's reference count will be greater than 1, dealloc never call to, This will happen if the memory leaks.

timer都会对它的target进行retain,我们需要小心对待这个target的生命周期问题,尤其是重复性的timer,同时需要注意在dealloc之前调用invalidate。

There are quite a few things that can be researched about the timer, such as it must be in the runloop, such as its time is certain? These are not related to the topic of this chapter, and we will not talk about it for the time being.

Questions about the Performselector:afterdelay
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay

We're still looking at the official documentation, and we want you to write a demo to verify that.

this method sets up a timer to perform the aselector message on the current thread ' s run loop. The timer is configured to run in the default mode ( Nsdefaultrunloopmode). When the timer is fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the Run loop is Running and in the default mode; otherwise, the timer waits until the Run loop is in the default mode.             

It probably means that the system relies on a timer to ensure that the delay is triggered, but only if runloop default mode it succeeds at that time, selector it will wait until run loop it is switched on default mode .
According to our previous timer statement, here actually calls Performselector:afterdelay: the same will cause the system to target strong references, also retain live. This way, if you can't do it all the time selector (for example, if runloop it's not running default model ), it can also cause a target memory leak that can't be released.
How to solve this problem?
In fact, it is very simple, we cancel the call at the appropriate time, the system provides an interface:

+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget

This function can be dealloc called in, you can think for yourself?
On the addobserver and removeobserver problems of nsnotification
We should notice that we will often dealloc call inside again, will not removeObserver the above problem?
The answer is no, because addObserver only a weak reference is created to the receiver, so there is no memory leak. But we need to dealloc call inside removeObserver , avoid the notification when the object has been destroyed, this time it will happen crash .

C-Language interface

The C language cannot call retain and release in OC, and the General C interface provides release functions (such as cgcontextrelease (context C)) to manage memory.ARC不会自动调用这些C接口的函数,所以这还是需要我们自己来进行管理的.

The following is a common drawing code, where you need to call the release interface yourself.

Cgcontextref context =Cgbitmapcontextcreate (NULL, Target_w, Target_h,8, 0, RGB, BMI); cgcolorspacerelease (RGB); uiimage *pdfimage = NIL; if (context! = null) { Cgcontextdrawpdfpage (context, page); cgimageref imageref = cgbitmapcontextcreateimage (context) ; cgcontextrelease (context); pdfimage = [uiimage imageWith< Span class= "hljs-built_in" >cgimage:imageref scale:screenscale orientation: Uiimageorientationup]; cgimagerelease (IMAGEREF);} else {cgcontextrelease (context);}     

In general, arc is very useful and can help you solve most of the memory leak problems. So it is recommended that you use arc directly, and try not to use MRC.

Memory issues to be aware of under arc

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.