IOS OC memory management
Van has gravity 2021-07-30 06:23:43

The goal is

1.【 understand 】 memory management

2.【 master 】 first MRC Program

3.【 master 】 Principles of memory management

4.【 understand 】 Wild pointer and zombie object

5.【 understand 】 Memory management of a single object

6.【 understand 】 Memory management of multiple objects

7.【 master 】set Method memory management

8.【 master 】@property Parameters

9.【 master 】@class keyword

10.【 understand 】 loop retain

One 、 memory management

The program will create a large number of objects in the heap space during running , When the object is no longer used , The system does not automatically free objects in heap space ( Basic data types are automatically managed by the system ). If an object is not released in time after it is created and used , Then the object will not be released until the end of the program , This will take up a lot of memory space . Other high-level languages such as C#、Java All through the garbage collection mechanism (GC) To solve this problem , But in OC There is no similar garbage collection mechanism in , Therefore, its memory management needs to be manually maintained by programmers . And stack space 、BSS paragraph 、 Data segment 、 The data in the code segment is automatically managed by the system , So the data in these areas does not need to be managed by programmers , We just need to manage the data in the heap space , That is to say OC The release of objects requires us to manage .

Reference counter

OC Memory management in depends on object reference counters , stay OC There is an integer corresponding to each object in the (retainCount), It's called “ Reference counter ”. When an object is created, its reference counter defaults to 1, If the reference counter of an object is 0, The system will automatically call the... Of this object dealloc Method to destroy this object .

Memory leak

An object is not recycled after use , It is not recycled until the end of the program , This phenomenon is called memory leak .

How to manipulate the reference counter of an object ?

Call the object's retain Method , The reference counter of the object will +1.

Call the object's release Method , The reference counter of the object will -1.

Call the object's retainCount Method , You will get the value of the reference counter of this object .

summary :

When we want to use an object , You should send a message for this object retain news . When we no longer use an object , You should send a message for this object release news . When the reference counter of the object is 0 When , The system will call this object dealloc Method to destroy this object , So we usually rewrite dealloc Method to monitor the destruction of objects .

Two 、 first MRC Program

OC Memory management is divided into MRC(Manual Reference Counting) Manual reference count and ARC(Automatic Reference Counting) Auto reference count . See the name and know the meaning ,MRC It is the programmer who manually records the reference count of the object , and ARC The system automatically records the reference count of the object . because ARC The mechanism is Xcode4.2 After the launch of , So by default Xcode It turns on automatically ARC The mechanism , We're going to use MRC You have to close ARC.

QQ20150725-1

In order to facilitate the release of monitoring objects , We often need to rewrite dealloc Method . And rewrite dealloc Methods need to follow some specifications , In subclass dealloc Method must finally call the parent class's dealloc Method .

 
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
28
29
30
31
32
33
34
35
36
//Person.h file
#import <Foundation/Foundation.h>
 
@interface Person : NSObject
 
@end
 
//Person.m file
#import "Person.h"
 
@implementation Person
 
// rewrite dealloc Method
- (void)dealloc {
    NSLog(@" Someone hung up ...");
    
    // In a subclass dealloc Method must finally call the parent class dealloc Method
    [super dealloc];
}
@end
 
//main.m file
#import <Foundation/Foundation.h>
#import "Person.h"
 
int main(int argc, const char * argv[]) {
    
    // Use alloc Create objects , The default object reference counter value is 1
    Person *p = [[Person alloc] init];
    
    // Send... To the object release The message just makes the reference counter -1, It does not necessarily make the object reference counter 0
    [p release];
    // Call the object's dealloc Method , Output
    // Someone hung up ...
    return 0;
}

 

3、 ... and 、 Principles of memory management

Send for the object only if someone is using it retain news , Send for an object only when a person no longer uses it release news . Follow who creates who release, who retain who release Principles .

 
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//Person.h file
#import <Foundation/Foundation.h>
 
@interface Person : NSObject
 
@end
 
//Person.m file
#import "Person.h"
 
@implementation Person
 
// rewrite dealloc Method
- (void)dealloc {
    NSLog(@" Someone hung up ...");
    
    // In a subclass dealloc Method must finally call the parent class dealloc Method
    [super dealloc];
}
@end
 
//main.m file
#import <Foundation/Foundation.h>
#import "Person.h"
 
int main(int argc, const char * argv[]) {
    
    // Use alloc Create objects , Reference counter +1
    Person *p = [[Person alloc] init];
    
    // Send a message to the object retain news , Reference counter +1
    [p retain];
    
    // to p Object to send a retainCount news , Returns the value of the reference counter
    NSUInteger count = [p retainCount];
    NSLog(@"count = %lu",count);
    
    // Send... To the object release The message just makes the reference counter -1, It does not necessarily make the object reference counter 0
    [p release];
    
    // Send another message release, At this point, the reference counter is 0 了
    [p release];
    // Call the object's dealloc Method , Output
    // Someone hung up ... 了 ...
    return 0;
}

 

Be careful :

1. Send... For the object release The message is not to let the object release , Instead, let the reference counter of the object -1.

2. When the value of the object reference counter is 0 when , The system will immediately call the... Of the object dealloc Method to release the object .

3. Create who release, who retain who release.

Four 、 Wild pointer and zombie object

C Wild pointers in language : A pointer variable points to a random memory space , That is, uninitialized pointer variables , This pointer is called a wild pointer .

OC Wild pointers in language : The object pointed to by the pointer has been released , This pointer is called a wild pointer .

Zombie object : Objects that have been released , It's called a zombie object , That is, the object accessed through the wild pointer is a zombie object . Note that once a pointer becomes a wild pointer , Don't access the members of an object through a wild pointer .

Every time you access an object through a pointer , Will check whether this object is a zombie object , If so, report an error . By default Xcode Will not automatically detect zombie objects , So how to turn on Xcode Automatic detection of zombie objects ?

QQ20150725-3

QQ20150725-2

When an object is recycled , Just assign a value to the pointer to this object nil, Avoid accessing zombie objects .

 
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
28
29
30
31
32
33
34
35
36
37
38
39
//Person.h file
#import <Foundation/Foundation.h>
 
@interface Person : NSObject
 
- (void)eat;
@end
 
//Person.m file
#import "Person.h"
 
@implementation Person
- (void)eat {
    NSLog(@" People eat ");
}
// rewrite dealloc Method
- (void)dealloc {
    NSLog(@" Someone hung up ...");
    // Call the parent class dealloc Method
    [super dealloc];
}
@end
 
//main.m file
#import <Foundation/Foundation.h>
#import "Person.h"
 
int main(int argc, const char * argv[]) {
    Person *p = [[Person alloc] init];
    //release Let the reference counter -1, At this time, the object reference counter is 0. Object destroyed
    [p release];
    
    //p Pointer assignment nil
    p = nil;
    
    // to p Object sends a message without an error , Nothing will happen
    [p eat];
    return 0;
}

 

5、 ... and 、 Memory management of a single object

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import <Foundation/Foundation.h>
#import "Person.h"
 
int main(int argc, const char * argv[]) {
    Person *p = [[Person alloc] init];//retainCount == 1
    [p retain];//retainCount == 2
    [p retain];//retainCount == 3
 
//    // Only retain No, release
    [p release];//retainCount == 2
    [p release];//retainCount == 1
    
//    // Assign a value to a pointer at an inappropriate time nil
//    p = nil;// The object hasn't been released yet , Just assign the pointer nil
    [p release];//retainCount == 0
    return 0;
}

 

6、 ... and 、 Memory management of multiple objects

When the property of one object is another object , In this property setter In the method , Put the incoming object first retain once , Then assign to the attribute . And in dealloc Method release.

 
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//Car.h file
#import <Foundation/Foundation.h>
 
@interface Car : NSObject
 
- (void)run;
@end
 
//Car.m file
#import "Car.h"
 
@implementation Car
-(void)run {
    NSLog(@" start the car ");
}
 
- (void)dealloc {
    NSLog(@" The car hung up ...");
    
    // Call the parent class dealloc Method
    [super dealloc];
}
@end
 
//Person.h file
#import <Foundation/Foundation.h>
#import "Car.h"
 
@interface Person : NSObject
@property Car *car;
 
- (void)drive;
@end
 
//Person.m file
#import "Person.h"
 
@implementation Person
 
- (void)setCar:(Car *)car {
    //retain Incoming objects , Because one more pointer (_car attribute ) Point to this incoming object
    //retain The return value is the object itself
    _car = [car retain];
}
 
- (void)drive {
    NSLog(@" start the car ");
    // call _car Of run Method
    [self.car run];
}
 
- (void)dealloc {
    NSLog(@" Someone hung up ...");
    // Let the car hang up when people hang up
    [self.car release];
    
    // Call the parent class dealloc Method
    [super dealloc];
}
@end
 
//main.m file
#import <Foundation/Foundation.h>
#import "Person.h"
 
int main(int argc, const char * argv[]) {
    // Instantiate people and car objects
    Person *p = [[Person alloc] init];
    Car *bmw = [[Car alloc] init];
    
    // Give someone a car
    p.car = bmw;
    
    // The object created after the first release
    [bmw release];
    bmw = nil;
 
    [p release];
    p = nil;
    return 0;
}

 

7、 ... and 、set Method memory management

 

 
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//Car.h file
#import <Foundation/Foundation.h>
 
@interface Car : NSObject
@property int speed;
 
- (void)run;
@end
 
//Car.m file
#import "Car.h"
 
@implementation Car
-(void)run {
    NSLog(@" start the car ");
}
 
- (void)dealloc {
    NSLog(@" The speed is %d The car hung up ...",_speed);
    
    [super dealloc];
}
@end
 
//Person.h file
#import <Foundation/Foundation.h>
#import "Car.h"
 
@interface Person : NSObject
@property Car *car;
@property NSString *name;
- (void)drive;
@end
 
//Person.m file
#import "Person.h"
 
@implementation Person
 
- (void)setCar:(Car *)car {
    // Determine whether the incoming object is the same object as the old value of the property
    if (_car != car) {
        // Not the same object release The old value
        [_car release];
        //retain The new value
        _car = [car retain];
    }
}
 
- (void)drive {
    // call _car Of run Method
    [_car run];
}
 
- (void)dealloc {
    NSLog(@"%@ Hang up ...",_name);
    // The object to which the property is pointed before the object is released release once , It means that it doesn't point to that object
    [_car release];
    
    [super dealloc];
}
@end
 
//main.m file
#import <Foundation/Foundation.h>
#import "Person.h"
 
int main(int argc, const char * argv[]) {
    // Instantiate two person objects
    Person *p1 = [[Person alloc] init];//p1 Of retainCount == 1
    Person *p2 = [[Person alloc] init];//p2 Of retainCount == 1
    // For two people _name assignment
    p1.name = @"jack";
    p2.name = @"rose";
    
    // Instantiate two car objects
    Car *bmw = [[Car alloc] init];//bmw Of retainCount == 1
    Car *benz = [[Car alloc] init];//benz Of retainCount == 1
    // For two car objects respectively _speed assignment
    bmw.speed = 100;
    benz.speed = 80;
    
    //p1 Point to bmw
    p1.car = bmw;//bmw Of retainCount == 2
    
    //p2 Point to bmw
    p2.car = bmw;//bmw Of retainCount == 3
    
    //p2 Don't point to bmw 了 , Point to benz
    p2.car = benz;//bmw Of retainCount == 2 , benz Of retainCount == 2
    
    [benz release];//benz Of retainCount == 1
    [p2 release];//p2 Of retainCount == 0 Called p2 Of delloc Method , Call again benz Of release. benz Of retainCount == 0   therefore rose Hang up ,benz I've also hung up
    [bmw release];//bmw Of retainCount == 1
    [p1 release];//p1 Of retainCount == 0 Called p1 Of delloc Method , Call again bmw Of release. bmw Of retainCount == 0   therefore jack Hang up ,bmw I've also hung up
    
    /* Output
    rose Hang up ...
     The speed is 80 The car hung up ...
    jack Hang up ...
     The speed is 100 The car hung up ...
     */
    return 0;
}

 

8、 ... and 、@property Parameters

QQ20150725-4

@property The parameters are divided into Three types of , Separated by commas , For each type of parameter, you can choose one of the three types of parameters in the figure above . If you do not set or only set one of the parameters , The program will use the default parameters of each of the three categories , Default parameters :(atomic,readwrite,assign).

Format :@property ([ Parameters 1, Parameters 2, Parameters 3]) data type name ;    // [] Is optional

Generally, in multithreading development, a property may be accessed by two or more threads at the same time , At this time, you can consider atomic attribute , Otherwise, it is recommended to use nonatomic, No locks , More efficient .readwirte Method will generate getter、setter Two methods , If you use readonly Then only getter Method . About setter Method handling requires special instructions , Suppose we define an attribute a, Here are three ways to generate code :

assign, For basic data types

 
1
2
3
- (void)setA:(int)a {
    _a = a;
}

retain, Usually used for non string objects

 
1
2
3
4
5
6
- (void)setA:(Car *)a {
    if(_a != a){
        [_a release];
        _a = [a retain];
    }
}

copy, Usually used for string objects

 
1
2
3
4
5
6
- (void)setA:(NSString *)a{
    if(_a != a){
        [_a release];
        _a = [a copy];
    }
}

We can specify... In the parameters @property Generated setter、getter Method name of , In general , When the type of the attribute is a BOOL When it comes to type , We can specify getter The method name is is start , This enhances code readability .

 
1
2
3
4
5
6
7
8
9
10
11
12
13
@property (nonatomic,assign,readwrite,getter=isRich) int rich;
 
// Generated setter、getter Method statement
- (void)setRich:(BOOL)rich;
- (BOOL)isRich;
 
// Generated setter、getter Method realization
- (void)setRich:(BOOL)rich {
    
}
- (BOOL)isRich {
 
}

Practical application cases

 
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//Book.h file
#import <Foundation/Foundation.h>
 
@interface Book : NSObject
@property (nonatomic, copy) NSString *bookName;
@end
 
//Book.m file
#import "Book.h"
 
@implementation Book
- (void)dealloc {
    NSLog(@"<<%@>> Burned ",_bookName);
    [_bookName release];
    
    [super dealloc];
}
@end
 
//Student.h file
#import <Foundation/Foundation.h>
#import "Book.h"
 
@interface Student : NSObject
@property (nonatomic, retain) Book *book;
@end
 
//Student.m file
#import "Student.h"
 
@implementation Student
- (void)dealloc {
    
    NSLog(@"<<%@>>",_book.bookName);
    [_book release];
    
    [super dealloc];
}
@end
 
//main.m file
#import <Foundation/Foundation.h>
#import "Student.h"
 
int main(int argc, const char * argv[]) {
    Student *stu = [[Student alloc] init];//stu Of retainCount == 1
    Book *book = [[Book alloc] init];//book Of retainCount == 1
    
    stu.book = book;//book Of retainCount == 2
    stu.book.bookName = @" Romantic girl ";
    
    [book release];//book Of retainCount == 1
    [stu release];//stu Of retainCount == 0, call stu Of dealloc Method , Call again book Of release, be book Of retainCount == 0
    
    /*
     Output
     The student hung up
     << Romantic girl >> Burned
     */
    return 0;
}

 

Nine 、@class keyword

When two classes contain each other , Will cause Dead cycle . stay .h The file cannot contain the header file of the class associated with itself , Because once included, it will cause an endless loop . You should use @class To declare that a class exists , If in .m You need to use... In the file @class When a member of a declared class , It's just .m Just include it in the file .

 
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//Book.h file
#import <Foundation/Foundation.h>
@class Student;// If you don't need to use members in the class, you can use @class Tell compiler ,Student Is a class
 
@interface Book : NSObject
@property (nonatomic, copy) NSString *bookName;
@property (nonatomic, assign) Student *owner;
 
- (void)showOwner;
@end
 
//Book.m file
#import "Book.h"
#import "Student.h"
 
@implementation Book
- (void)showOwner {
    // Used Student Class members _name, Just include the file header directly
    NSLog(@"%@ My master is %@",self.bookName,self.owner.name);
}
- (void)dealloc {
    NSLog(@" Book hanging ");
    [_bookName release];
    [super dealloc];
}
@end
 
//Student.h file
#import <Foundation/Foundation.h>
@class Book;// If you don't need to use members in the class, you can use @class Tell compiler ,Book Is a class
 
@interface Student : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, retain) Book *book;
 
- (void)showBook;
@end
 
//Student.m file
#import "Student.h"
#import "Book.h"
 
@implementation Student
- (void)showBook {
    // Used Book Class members _bookName, Just include the file header directly
    NSLog(@"%@ My book is called %@",self.name,self.Book.bookName);
}
- (void)dealloc {
    NSLog(@" Students hang up ");
    [_name release];
    [_book release];
    [super dealloc];
}
@end

 

Ten 、 loop retain

When two classes refer to each other , If two classes of @property The parameters of are retain There will be a memory leak caused by circular reference . The solution is to use a class retain, Another class uses assign. Use assign Your class doesn't have to be in dealloc Method for that property release.

 
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//Book.h file
#import <Foundation/Foundation.h>
@class Student;// tell Book,Student Is a class
 
@interface Book : NSObject
@property (nonatomic, copy) NSString *bookName;
@property (nonatomic, assign) Student *owner;// Use assign
 
@end
 
//Book.m file
#import "Book.h"
 
@implementation Book
 
- (void)dealloc {
    NSLog(@"<<%@>> Release ",self.bookName);
    [super dealloc];
}
@end
 
//Student.h file
#import <Foundation/Foundation.h>
@class Book;// tell Student,Book Is a class
 
@interface Student : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, retain) Book *book;// Use retain
 
@end
 
//Student.m file
#import "Student.h"
 
@implementation Student
 
- (void)dealloc {
    NSLog(@"<<%@>> The release of the ",self.name);
    [_book release];
    [super dealloc];
}
@end
 
//main.m file
#import <Foundation/Foundation.h>
#import "Book.h"
#import "Student.h"
 
int main(int argc, const char * argv[]) {
    Book *book = [[Book alloc] init];//book Of retainCount == 1
    book.bookName = @" Romantic girl ";
    
    Student *student = [[Student alloc] init];//student Of retainCount == 1
    student.name = @" Brother Niubi ";
    
    book.owner = student;// the reason being that assign, So not retain Incoming student, be student Of retainCount == 1
    student.book = book;// the reason being that retain, Meeting retain Incoming book, be book Of retainCount == 2
    
    [student release];//student Of retainCount == 0, Would call student Of dealloc Method , Call again book Of release. be book Of retainCount == 1
    student = nil;
    
    [book release];//book Of retainCount == 0
    book = nil;
    
    /* Output
     << Brother Niubi >> The release of the
     << Romantic girl >> Release
     */
    return 0;
}
Write the code ,change the world!
Please bring the original link to reprint ,thank
Similar articles