What exactly did ARC do for us? _arc

Source: Internet
Author: User
Tags assert garbage collection goto modifiers prepare prev
About ARC

Starting with iOS5, the automatic reference count (Automatic Reference counting, ARC) is supported, so it becomes simpler. Arc Almost all memory management matters to the compiler to determine, developers only need to focus on business logic. Some ideas about arc

1.ARC is similar to a Java GC and can result in some loss of performance.
First, ARC and GC are different, and arc is the compile-time compiler that "helps you" insert memory management code that would otherwise have to be handwritten, rather than a garbage collection system that runs like a GC.

2.ARC does not manage the memory itself, it will not appear memory leaks, or lead to uncontrolled memory fluctuations?
After understanding the principles of arc, you know, the code of the memory management that the compiler inserts in the arc is optimized, for use of memory, running a line of code is not wasted, so to speak, handwritten memory management must reach a very strict level to be able to achieve arc automatically generated as complete and without omissions. Method naming rules in OC

If the method name starts with the following words, its returned object is owned by the caller: alloc, new, copy, mutable copy. If you invoke the method above, you are responsible for releasing the returned object. In other words, these objects require you to manually release them in the MRC. If the method name does not begin with the four words above, the returned object does not need you to manually release it, because a autorelease method will be executed automatically within the method.
Specifically what can be read another blog post effective OC within the management. What optimizations does ARC have?

This article is just a few examples to illustrate what arc does, just glimpse, ARC does a lot of other things, and optimization.

When using arc, be sure to remember that the reference count is actually performed, except that the retention and release operation is now automatically added to you by the arc. In fact, when invoking these methods, ARC does not pass the normal objective-c message distribution mechanism, but rather calls its underlying C-language version directly. This is better performance because retention and release operations require frequent execution, so calling the underlying function directly can save a lot of CPU cycles. Using compilations to find answers

In the Xcode of Product->perform action->assemble "SOMECLASS.M", we can see that the OC source file was eventually compiled to compile the assembly code of the production, Here you can see in detail exactly what code the compiler inserted behind our code.

I have built a class zoo:

@interface zoo:nsobject
+ (instancetype) Createzoo;
+ (instancetype) Newzoo;
@end

@implementation Zoo
+ (instancetype) Createzoo {return
    [self new];
}
+ (Instancetype) Newzoo {return
    [self new];
}
@end

The Createzoo and Newzoo methods for converting ZOO.M into compilations are as follows:

To see the Createzoo method and the Newzoo method, there are two runtime methods:
Objc_msgsend (lines 34 and 68): Sends message new to class object.
Objc_autoreleasereturnvalue (39 lines): This function is equivalent to replacing us by manually calling Autorelease, and there are some optimizations. The compiler detects the following code, sets a flag bit in the global data structure based on whether the returned object performs a retain operation, and decides whether to perform the autorelease operation.
You can ignore these effects first and have a more detailed description later. Here we just need to know how to translate the code into a compilation, and we'll keep looking.

The code in VC:

@interface Viewcontroller ()
@property (nonatomic, strong) Zoo *zoo;
@end

@implementation Viewcontroller
-(void) viewdidload {
    [super viewdidload];
    [Self Testforarc];
}
-(void) Testforarc {
    //the method that requires manual release of the returned object
    [Zoo Newzoo];               Scenario 1
    //id TEMP1 = [Zoo Newzoo];    Scenario 2
    //Self.zoo = [Zoo Newzoo];    Scenario 3

    //No need to manually release the return object method
    //[Zoo Createzoo];            Scenario 4
    //id TEMP2 = [Zoo Createzoo];//Scenario 5
    //Self.zoo = [Zoo Createzoo];//Scenario 6
}

@end
You need to manually release the method that returns the object

Scenarios 1, 2, and 3 are all methods that start with new, and the returned objects are owned by the caller, so you need to manually release the method that returns the object. When we test scenario 1, we annotate the code for other stories to increase the readability of the assembly. Scenario 1

Scenario 1, VC to the assembly:

As you can see, the code line in the yellow box in VIEWCONTROLLER.M is line 35th, which is the code for Scenario 1. There are two runtime functions, that is, the function in the red box:
Objc_msgsend (83 lines): Send Message to Zoo Createzoo.
Objc_release: Frees the object returned by [Zoo Newzoo].
So this is the way that arc automatically adds code:

Zoo
+ (instancetype) Newzoo {return
    [self new];
}
VC
-(void) TESTFORARC {
    id temp = [Zoo Newzoo];
    Objc_release (temp);
}
Scenario 2

Scenario 2, VC to the assembly:

So this is the way that arc automatically adds code:

Zoo
+ (instancetype) Newzoo {return
    [self new];
}
VC
-(void) Testforarc {
    id temp1 = [Zoo Newzoo];
    Objc_storestrong (&TEMP1, nil);   Equivalent to release
}

The internal implementation of the Objc_storestrong is as follows:

void Objc_storestrong (ID *location, id obj) {
    id prev = *location;   
    if (obj = = prev) {return
        ;    
    }    
    Objc_retain (obj);    
    *location = obj;    
    Objc_release (prev);
}
Scenario 3

VC back-Check the Testforarc method after compilation:

VC back-Check the Setzoo method after compilation:

So, VC in the code should be like this:

Zoo
+ (instancetype) Newzoo {return
    [self new];
} 
VC
-(void) TESTFORARC {
    id temp = [Zoo Newzoo];
    [Self setzoo:temp];
    Objc_release (temp);
}
-(void) Setzoo: (Zoo *zoo) {
    Objc_storestrong (&_zoo, Zoo);
}
You do not need to manually release a method that returns an object

Scenario 4, 5, 6, named rules, the returned object is not owned by the caller, so there is no need to manually release the method that returns the object. Scenario 4

Scenario 4, VC to the assembly:

VC in the code should be like this:

Zoo
+ (instancetype) createzoo {
    id temp = [self new];  
    return Objc_autoreleasereturnvalue (temp); 
} 
VC
-(void) Testforarc { 
    objc_unsafeclaimautoreleasedreturnvalue ([Zoo Createzoo]); 
}

Objc_autoreleasereturnvalue: This function is equivalent to replacing us by manually calling Autorelease, and there are some optimizations. The compiler detects the following code, sets a flag bit in the global data structure based on whether the returned object performs a retain operation, and determines whether the autorelease operation is performed. The tag has two states, the RETURNATPLUS0 represents the execution autorelease, and the RETURNATPLUS1 representative does not perform the autorelease.
Objc_unsafeclaimautoreleasedreturnvalue: The function is to manually call the Objc_release function for us, and there are some optimizations. The compiler depends on the stored tag to decide that it needs no release operations, and of course it does not need to be autorelease if it is created. Scenario 5

Scenario 5, VC to the assembly:

VC in the code should be like this:

Zoo
+ (instancetype) Createzoo  {
    id temp = [self new]; 
    return Objc_autoreleasereturnvalue (temp);
} 
//VC
-(void) Testforarc { 
    id temp2 = Objc_retainautoreleasedreturnvalue ([Zoo Createzoo]); 
    Objc_storestrong (&TEMP2, nil); Equivalent to release
}

Objc_retainautoreleasedreturnvalue: This function will replace the Retain method in MRC, and this function will also detect the flag bit mentioned just now, depending on the flag bit to determine whether to perform the retain operation.
In this example, because the object is not persisted in the code, the flag bit state of the Objc_autoreleasereturnvalue function set at the time of creation is supposed to be ReturnAtPlus0, indicating that the autorelease action needs to be performed. So, the function here is retain operation. Scenario 6

VC back-Check the Testforarc method after compilation:

VC back-Check the Setzoo method after compilation:

VC in the code should be like this:

Zoo
+ (instancetype) Createzoo  {
    id temp = [self new]; 
    return Objc_autoreleasereturnvalue (temp);
}
VC
-(void) TESTFORARC {
    id temp = _objc_retainautoreleasedreturnvalue ([Zoo Createzoo]); 
    [Self setzoo:temp];
    Objc_release (temp);
}
-(void) Setzoo: (Zoo *zoo) {
    Objc_storestrong (&_zoo, Zoo);
}

In this example, because the Zoo property in the code retains the object, the flag bit state of the Objc_autoreleasereturnvalue function set at the time of creation should be RETURNATPLUS1, indicating that no autorelease action is required. Therefore, the function is not retain at this point, so the reference count is the one at the time of creation, and no extra action is done. And the method of setting and detecting the flag bit through arc is quicker than calling Autorelease and retain. Optimization of variable modifiers

In the application, modifiers change the semantics of local variables and instance variables: __strong, __unsafe_unretained, __weak, __autorelease. The concrete meaning does not have to be mentioned, may ask me my previous blog: Effective OC within the management.
Now simply to study the semantics of modifiers, the need to manually release the return object in the context of the background to make comparisons, modify the VC Testforarc method:

-(void) Testforarc {
//other method
    id objc1 = [Zoo Newzoo];                      Scenario 7 (Consistent with scenario 2)
//    __weak id objc2 = [Zoo Newzoo];               Scenario 8
//    __unsafe_unretained id objc3 = [Zoo Newzoo];  Scenario 9
//    __autoreleasing id objc4 = [Zoo Newzoo];      Scenario Ten
}
__strong (Scenario 7)

When you create an object, the default is strong, so in these comparisons, scenario 7 is consistent with scenario 2, so you don't have to repeat it. __weak (Scenario 8)

VC back-Check the Testforarc method after compilation:

VC in the code should be like this:

-(void) TESTFORARC {
    id temp = [Zoo Newzoo]; 
    Objc_initweak (&OBJC2, temp);
    Objc_release (temp);
    Objc_destroyweak (&OBJC2);
}

This process is a cycle of weak pointers, from creation to destruction. Here are two new runtime functions, Objc_initweak and Objc_destroyweak. These two functions are responsible for creating weak pointers and destroying weak pointers. In fact, both of these functions refer to another runtime function, Storeweak, which is a function corresponding to the Storestrong.
Their source code is as follows:

Objc_initweak (ID *location, id newObj)
{
    if (!newobj) {
        *location = nil;
        return nil;
    }

    Return Storeweak<donthaveold, Dohavenew, docrashifdeallocating>
        (location, (objc_object*) newObj);
void
objc_destroyweak (id *location)
{
    (void) storeweak<dohaveold, donthavenew, Dontcrashifdeallocating>
        (location, nil);
}
__unsafe_unretained (Scenario 9)

VC back-Check the Testforarc method after compilation:

VC in the code should be like this:

-(void) TESTFORARC {
    id temp = [Zoo Newzoo]; 
    Pointer objc3 Assignment procedure
    objc_release (temp);
}

__unsafe_unretained type, does not have ownership, so just simple pointer assignment, no runtime function to use. When the TEMP variable is destroyed, the pointer objc3 still points to that memory, so it is not unsafe. As its name, unretained, unsafe. __autoreleasing (Scenario 10)

VC back-Check the Testforarc method after compilation:

VC in the code should be like this:

-(void) Testforarc {
    id objc4 = [Zoo Newzoo]; 
    Objc_autorelease (OBJC4);
}

After using the __autorelease modifier, it is equivalent to adding a autorelease to it, releasing it when the Autoreleasepool is destroyed. Add Autoreleasepool Manually

As we all know, the compiler will add some autorelease for us in the system creation autoreleasepool, releasing the time when the pool POPs are automatically released. Also, manually added Autoreleasepool will pop out immediately after the scope of the free pool has ended. First look at the code:

-(void) Testforarc {
    @autoreleasepool {
        id objc5 = [Zoo Newzoo];                    Scenario one
//        __autoreleasing id objc6 = [Zoo Newzoo];    Scenario
//        __autoreleasing id objc7 = [Zoo Createzoo];//Scenario
    }
}
Scenario 11

VC back-Check the Testforarc method after compilation:

VC in the code should be like this:

-(void) Testforarc {
     @autoreleasepool {
        id objc5 = [Zoo Newzoo];
        Objc_storestrong (&objc5, nil);
    }

Scenario 11 is actually on the basis of scenario 2, the outer bread of a layer of autoreleasepool, the result is not very different, this is more than a objc_autoreleasepoolpush and objc_autoreleasepoolpop. Understand the principle of automatic release of eating you will understand that the automatic release pool that was manually added is so that the scope will be released. My previous blog has written to the autorelease mechanism and the opportunity to release, here is not a statement. Scenario 12

VC back-Check the Testforarc method after compilation:

VC in the code should be like this:

-(void) Testforarc {
     @autoreleasepool {
        id objc6 = [Zoo Newzoo];
        Objc_autorelease (OBJC6);
    }

When you add a __autorelease modified variable to the Autoreleasepool, you add a autorelease to it, releasing it when the Autoreleasepool is destroyed. This is a manually added Autoreleasepool, so it is released as soon as the pool Objc_autoreleasepoolpop is released. The same applies to scenario 13 below. Scenario 13

VC back-Check the Testforarc method after compilation:

VC in the code should be like this:

-(void) Testforarc {
    @autoreleasepool {
         id objc7 = _objc_retainautoreleasedreturnvalue ([Zoo Createzoo]); 
         Objc_autorelease (OBJC7);}}
Realization of memory management function in runtime

In the runtime source code, there are some memory-managed functions whose declarations exist in the Objc-internal.h file. For example, Objc_alloc (), Objc_allocwithzone (), Objc_retain (), Objc_release (), Objc_autorelease (), Objc_autoreleasepoolpush, Objc_autoreleasepoolpop, these functions should be read by name.

There are also a few, of course, including the above mentioned, Objc_autoreleasereturnvalue (), Objc_unsafeclaimautoreleasedreturnvalue (), objc_ Retainautoreleasedreturnvalue (), Objc_storestrong (), Objc_weakstrong, Objc_initweak (), Objc_destroyweak () Their inner implementations are simple to talk about.

1.objc_storestrong ()

void Objc_storestrong (ID *location, id obj) {
    id prev = *location;   
    if (obj = = prev) {return
        ;    
    }    
    Objc_retain (obj);    
    *location = obj;    
    Objc_release (prev);
}

When you see this source code, you will find that this is an optimization done in arc. And look at the code below, if the reference count of object after release drops to 0, causing the system to recycle it, and then perform the retain operation, which will crash the application. This omission is not possible after the arc is used. ARC automatically preserves the new values, releases the old values, and finally sets the instance variables so that they are securely stored.

-(void) SetObject: (ID) object {
    [object release];
    _object = [object retain];
}

2.storeWeak ()
It is a function corresponding to the Storestrong:

Static ID storeweak (ID *location, Objc_object *newobj) {assert (Haveold | |
    Havenew);

    if (!havenew) assert (NEWOBJ = = nil);
    Class Previouslyinitializedclass = nil;
    ID oldobj;
    Sidetable *oldtable;

    Sidetable *newtable;
    Acquire locks for the old and new values. 
    Order by lock address to prevent lock ordering problems.
 Retry if the old value changes underneath us.
        Retry:if (haveold) {oldobj = *location;
    oldtable = &sidetables () [Oldobj];
    else {oldtable = nil;
    } if (havenew) {newtable = &sidetables () [NEWOBJ];
    else {newtable = nil;

    Sidetable::locktwo 

The first is to find the old object that it points to according to the weak pointer, it then gets to the Sidetable object associated with the old object, removes the information in the weak table of the older objects, establishes the association information in the new object's weak table, and then lets the weak reference pointer point to the new object and returns.

3.objc_initweak ()

Objc_initweak (ID *location, id newObj)
{
    if (!newobj) {
        *location = nil;
        return nil;
    }

    Return Storeweak<donthaveold, Dohavenew, docrashifdeallocating>
        (location, (objc_object*) newObj);

4.objc_destroyweak ()

void
objc_destroyweak (id *location)
{
    (void) storeweak<dohaveold, donthavenew, Dontcrashifdeallocating>
        (location, nil);
}

5.objc_retainautoreleasereturnvalue ()

Prepare a value at +0 for return through a +0 autoreleasing convention.
ID objc_retainautoreleasereturnvalue (ID obj)
{
    if (Prepareoptimizedreturn (RETURNATPLUS0)) return to obj;

    Not Objc_autoreleasereturnvalue (Objc_retain (obj)) 
    //Because we don t need another
    optimization attempt return Objc_retainautoreleaseandreturn (obj);
}

6.objc_retainautoreleasedreturnvalue ()

Accept a value returned through a +0 autoreleasing convention for use at +1.
ID objc_retainautoreleasedreturnvalue (ID obj)
{
    if (acceptoptimizedreturn () = = ReturnAtPlus1) return obj;

    return Objc_retain (obj);
}

Pseudo code is as follows:

ID objc_retainautoreleasedreturnvalue (ID object) {
    if (Get_flag (object))  {
        Clear_flag (object);
        return object;
    } else {return
        [object retain];
    }
}

7.objc_unsafeclaimautoreleasedreturnvalue ()

Accept a value returned through a +0 autoreleasing convention for use at +0.
ID objc_unsafeclaimautoreleasedreturnvalue (ID obj)
{
    if (acceptoptimizedreturn () = = ReturnAtPlus0) return obj ;

    return Objc_releaseandreturn (obj);
}

Pseudo code is as follows:

ID objc_unsafeclaimautoreleasedreturnvalue (ID object) {
    if (Get_flag (object))  {return
        [object release];
    else {
        Clear_flag (object);
        return object;
    }

8.objc_autoreleasereturnvalue ()

Prepare a value at +1 for return through a +0 autoreleasing convention.
ID objc_autoreleasereturnvalue (ID obj)
{
    if (Prepareoptimizedreturn (RETURNATPLUS1)) return to obj;

    return objc_autorelease (obj);
}

Pseudo code is as follows:

ID objc_autoreleasereturnvalue (ID object) {
    if (///The caller will execute retain) {
          Set_flag (object);
          return object;
    } else {return
          [object autorelease];    
    }
}

There are other run-time methods that can be used normally, such as objc_destructinstance (), Objc_duplicateclass (), Objc_destructinstance (), and so on, Want to know can go to the following address to download.

This article Demo Source: Demo_arc Inquiry
Recommended article reading: Effective OC within storage management
Runtime source Download Address: Runtime source
OpenSource objc4:https://opensource.apple.com/tarballs/objc4/

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.