内存管理(Memory Management,retain, dealloc,new,copy,MRC)

内存管理(Memory Management)

        内存管理的方式

        垃圾回收机制(gc, garbage collection), 油系统管理内存, 开发人员不需要关心内存, 系统会自动检测, 自动释放, 比如java

        : OC1.0不支持垃圾回收机制, 2.0时支持来及回收机制, 但是在iOS平台上苹果把OC的垃圾回收机制屏蔽掉了

        iOS不支持垃圾回收机制, 如何管理内存?

        通过引用计数(retain count)管理内存

        通过引入计数来管理内存, 有两种方式

        1.MRC, Manual Reference Count, 手动引用计数, 由开发人员通过引入计数来管理内存

       MRC设置

        2.ARC, Automatic Reference Count, 自动引入计数, 由系统通过引入计数来管理内存

        图中行为   OC操作                   OC方法

        开灯      开辟内存空间, 生成对象      alloc/new/copy

        需要照明   持有对象                  retain/copy

        不需要照明释放对象                  release/autorelease

        关灯      回收内存空间, 丢弃对象      dealloc

        : 需要照明的人数, 就是引入计数

        持有: 只要对这个对象做了引用计数+1的操作, 就叫人持有了这个对象

        alloc, 从堆区开辟内存空间

        引用计数: 0变成1

        自己创建的对象, 自己持有

        Light *light = [[Light alloc] init];
        NSLog(@"%lu", light.retainCount);

        retain, 引用计数+1

        持有某个对象

        [light retain];
        NSLog(@"%lu", light.retainCount);

安全使用对象: 先持有, 再使用

        release, 引用计数-1

        不再使用某个对象时, 释放该对象

        [light release];
        NSLog(@"%lu", light.retainCount);  
        [light release];//light.retainCount = 0
//        NSLog(@"%lu", light.retainCount);

 僵尸对象

        当对象的引入计数为0, 就不能再使用这个对象了, 如果再使用这个对象, 对象就会变成僵尸对象

        dealloc, 回收内存, 不允许手动调用, 当引用计数变成0时自动调用dealloc方法 

Light.m
#import "Light.h"
@implementation Light
- (void)dealloc
{
    NSLog(@"关灯(回收内存)");
    [super dealloc];
}
@end

        new, 相当于alloc + init

        Light *light1 = [[Light alloc] init];
        Light *light2 = [Light new];
        NSLog(@"%lu, %lu", light1.retainCount, light2.retainCount);
        [light1 release];
        [light2 release];

autorelease, 自动释放, 在未来的某段时间, 引用计数-1

        Light *light3 = [[Light alloc] init];
        [light3 autorelease];
        NSLog(@"%lu", light3.retainCount);

 : 对一个对象使用autorelease操作, 这个对象不回立刻引用计数-1, 而是先放到自动释放池中, 当自动释放池结束, 会对池中的对象依次做引用计数-1

 autoreleasepool只对调用了autorelease的对象起作用

 copy

前提: 必须遵守<NSCopying>协议

        Light *lightA = [[Light alloc] init];       
        Light *lightB = [lightA copy];
        NSLog(@"%@", lightA);
        NSLog(@"%@", lightB);     
        [lightA release];
        [lightB release];

 浅拷贝: 拷贝指针, 内存地址空间一样

        lightB = [lightA retain];

深拷贝: 拷贝内存空间, 内存地址空间不一样

Light.m
- (id)copyWithZone:(NSZone *)zone { //zone: 内存空间 //1.深拷贝 Light *light = [[Light allocWithZone:zone] init]; return light; //2.浅拷贝 // return [self retain]; }

内存管理的原则

        1.引用计数+1的操作(alloc, new, copy, retain)的次数 = 引用计数-1的操作(release, autoreleasse)的次数

        2.对象的引用计数变为0就不能使用该对象

        3.谁创建谁释放想使用先持有

        4.当不使用某个对象时要及时释放

        只有堆区的内存需要管理其他由系统管理

        NSString *string = @"辉哥真帅!";
        NSLog(@"%lu", string.retainCount);
        [string release];
        NSLog(@"%lu", string.retainCount);
        [string retain];
        NSLog(@"%lu", string.retainCount);
        
        NSString *str = [[NSString alloc]initWithFormat:@"辉哥帅的无法形容O(∩_∩)O哈哈哈~"];
        NSLog(@"%lu", str.retainCount);
        [str release];

NSString,创建字符串, 判断常量区内有没有, 如果有就返回常量区的字符串; 如果没有, 就从堆区开辟一块内存区域存放字符串

        NSString *str1 = [[NSString alloc] initWithFormat:@"1234567"];
        NSLog(@"%lu", str1.retainCount);
        [str1 release];
Person.h
#import <Foundation/Foundation.h>
//姓名 性别 年龄
//自定义初始化方法
//便利构造器
//重写description方法
@interface Person : NSObject
//属性的修饰词的默认值
//atomic, assign, readwrite
@property (nonatomic, retain) NSString *name;
@property (nonatomic, copy) NSString *gender;
@property (nonatomic, assign) NSInteger age;
- (instancetype)initWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age;
+ (instancetype)personWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age;
@end
Person.m
#import "Person.h"
@implementation Person
@synthesize age = _age, name = _name, gender = _gender;
//修饰词是assign的setter和getter的实现
- (void) setAge:(NSInteger)age {
    _age = age;
}
- (NSInteger)age {
    return _age;
}
- (void)dealloc
{
    [_name release];
    [super dealloc];
}
//修饰词是retain的setter和getter的实现
- (void)setName:(NSString *)name {
    if (_name != name) {//判断新对象的地址和原对象的地址是否一致, 如果一致, 就不需要改变; 如果不一致, 才需要改变
        [_name release];//释放原来对象, 拥有新对象
        _name = [name retain];//先持有, 才能安全使用
    }
}
- (NSString *)name {
    return  _name;
}
//修饰词是copy的setter和getter的实现
- (void)setGender:(NSString *)gender {
    if (_gender != gender) {
        [_gender release];
        _gender = [gender copy];
    }
}
- (NSString *)gender {
    return _gender;
}
- (instancetype)initWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age {
    if (self = [super init]) {
        _name = name;
        _gender = gender;
        _age = age;
    }
    return  self;
}
+ (instancetype)personWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age {
    return [[Person alloc] initWithName:name gender:gender age:age];
}
- (NSString *)description {
    return [NSString stringWithFormat:@"name:%@ gender:%@ age:%ld", _name, _gender, _age];
}
@end
        NSString *nameString = [[NSString alloc] initWithFormat:@"adasfdhgvjhk"];       
        Person *person = [[Person alloc] init];
        person.age = 18;
        person.name = nameString;
        [nameString release];       
        NSString *nameString1 = [[NSString alloc] initWithFormat:@"dfdfdfdf"];
        person.name = nameString1;
        [nameString1 release];        
        [person release];

创建池子的两种写法

写法1

    @autoreleasepool {
        Light *light4 = [[Light alloc] init];
        [light4 autorelease];
    }

写法2

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    Light *light5 = [[Light alloc] init];
    [light5 autorelease];
    [pool release];

 

 

The one who wants to wear a crown must bear the weight!
原文地址:https://www.cnblogs.com/OrangesChen/p/4872607.html