[黑马IOS自学第十五篇]对象内存管理

对象内存管理

 

栈区局部变量 (地址从高到低分配)局部变量的空间会自动回收

堆区存放程序运行过程中动态分配-存储空间(从低到高分配)

管理范围:管理人和继承自nsobject对象,Ocnew类的实例对象类会继承nsobject对象,对其他基本数据类型无效,先释放堆区的,在释放栈区

计算机生成了可选文字:本 质 因 是 因 为 对 和 荑 他 数 类 在 中 的 存 储 空 闷 不 一 样 · 它 , 变 量 主 要 存 于 中 · 而 对 存 储 于 中 · 当 代 码 块 结 束 时 这 个 代 码 块 中 涉 及 的 所 有 翩 变 量 会 被 回 收 · 指 向 对 象 的 指 针 也 被 回 收 , 此 时 对 象 己 经 漫 有 指 针 指 向 , 但 依 然 存 在 于 内 存 中 , 成 内

计算机生成了可选文字:厭 . · 10 对 象 类 型 是 程 序 运 行 过 程 中 动 态 分 配 的 , 存 储 在 堆 区 内 存 管 埋 主 要 是 对 堆 区 中 对 象 的 内 存 管 理 本 敵 癸 型 数 , 因 为 占 用 的 存 储 空 间 足 固 定 的 , 一 穀 存 在 棧 区

程序启动的时候就加载到内存(全局变量尽可能少用)由系统自动管理

bss未初始化的全局变量和静态变量

数据区已经初始化的全局变量静态变量字符串常量

代码段代码编译过后的内容


微信飞机射击的游戏

子弹对象:不在可见区域的时候要释放掉

闪退:软件占用移动内存超过多少M之后就会崩溃,超过20M会发送MemoryWarning消息,回收一些不需要再继续使用的内存空间,比如一些不再使用的对象和变量等,否则程序崩溃

ios的平台内存软件控制的特别好



内存管理的原理及分类

计算机生成了可选文字:对 象 所 有 权 概 念 任 何 对 象 都 可 能 拥 有 一 个 或 多 个 所 有 者 , 只 要 一 个 对 象 至 少 还 拥 有 一 个 所 有 者 , 它 就 会 继 续 存 在 Person *p = C(Person alloc) init); 。 obiect . " ' 0m1 、 “ than zeo; 0

*P的所有权为1,所有者就是自己,分配的存储空间有一个指针指向他

任何自己创建的对象都归自己所有,可以使用alloc,new,开头,或者名字中包含copy

的方法创建对象时,可以使用retain获取一个对象的所有权

 

对象的引入计数(用来保存当前对象有几个东西在使用它)

retainCount引用计数器

及多少个东西在引用这个对象

一个对象创建之后,最少有一个应用者

计算机生成了可选文字:" NSObject retainCount


没有对象内部,有八个字节存储空间来存储引用计数器

引入计数器作用

1.判断对象是否回收的依据,为0表示要回收了

2.一个对象的值为nil时候,引用计数器为0,但不回收

Person *p=nil;不用回收,因为没有创建内存空间


引用计数器操作

计算机生成了可选文字:给 对 象 发 送 消 息 , 进 行 相 应 的 计 數 器 操 作 。 | 奔 丶 retainiH,U: 使 计 数 器 + 1, 该 方 法 返 回 对 象 本 : release*H,U: 使 计 數 器 一 1 ( 并 不 代 表 释 放 对 象 ) retainCountiHE,: 获 得 对 象 当 前 的 引 用 计 數 器 值 %ld %tu

对象的销毁()

1.对象被释放的时候,系统发送一条dealloc消息,一般重写dealloc

2.一旦重写就必须在dealloc方法内部调用 [super dealloc ]调用,并且在代码块的最后调用

3.一旦对象被回收,他所占用的存储空间不再可用,坚持使用会导致程序崩溃

计算机生成了可选文字:当 一 个 对 象 的 引 用 计 数 器 为 0 时 , 那 么 它 将 被 销 毁 , 其 占 用 的 内 存 被 系 统 回 收 。 当 对 象 被 销 毁 时 , 系 统 会 自 动 向 对 象 发 送 一 条 dealloc 消 息 , 一 般 会 重 写 deall 方 法 , 在 这 里 释 放 相 关 的 资 源 , dealloc 就 像 是 对 象 的 “ 临 终 遗 訁 ” 一 旦 重 写 了 dealloc 方 法 就 必 须 调 用 (super dealloc), 并 且 放 在 代 码 块 的 最 后 调 用 ( 不 能 百 接 调 用 dealloc 方 法 ) 一 旦 对 象 被 回 收 了 , 那 么 他 所 占 据 的 存 储 空 间 就 不 再 可 用 , 持 仗 用 会 导 致 程 序 崩 濞 ( 野 指 针 错 课 ) 1) 如 果 对 象 的 计 数 器 不 为 0 , 那 么 在 整 个 程 序 运 行 过 程 , 它 占 用 的 内 存 就 不 可 能 被 回 收 ( 除 非 整 个 程 序 己 经 退 出 ) 2 ) 任 何 一 个 对 象 , 刚 生 下 来 的 时 候 , 引 用 计 器 都 为 1, ( 对 象 一 旦 创 建 好 , 默 认 引 用 计 器 就 是 3 ) 当 使 用 alloc 、 new 或 者 copy 创 建 一 个 对 象 时 , 对 象 的 引 用 计 數 器 默 认 就 是 1

 

OC内存管理分类,

MRC手动管理内存MannuReference Counting 需要手动retain,release,autorelease

ARCautomaticreferencecounting自动引用计数

Garbagecollection垃圾回收ios不支持垃圾回收macos支持

理解mrc尽量使用arc

苹果底层都是MRC,公司历史遗留的项目也有用MRC

计算机生成了可选文字:{app_code} fapp_code) (арр_собе} (арр-собе} fapp_code} {арр_собе} (арр_с обе) Орр_с Qde} арр_с Qde} арр_с

 

手动内存快速入门

关闭ARC方法

计算机生成了可选文字:My Mac PROJECT TARGETS Ready source Today at ags auto Ived Multiple valu... C Resolved Resolved Yes (Aggressi... C L@ultiple Val... C No C Bui d Settings Levels Build Phases Combined Build Options Setting Enable Testability Debug Release m main.m Products Yes v Yes (Aggress... C No v No C Apple LLVM 7.0 - Language - Objectiv Objective-C Automatic Reference Counting Apple LLVM 7.0 - Warnings - All languages Setting Uninitialized Variables


#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
       //
       
       Person  *p = [Person new];
       
       NSLog(@"retain= %ld",[p retainCount]) ;
        //typedefunsigned long NSUInteger;
       //占八个字节
        //NSLog(@"%ld",sizeof([p retainCount]));
       
       
        //引用计数器 + 1
        //Person *p2 = p;    //retainCount的还是1
 //      Person *p2 = [p retain];
       
       
         //引用计数器 + 1
       [p retain];
       NSLog(@"retain= %ld",[p retainCount]) ;//2
       
       [p release];
       NSLog(@"retain= %ld",[p retainCount]) ;//1
       [p release];
       
       
    }
    return 0;
}

2015-12-17 15:11:23.843内存管理-MRC管理[8484:1270933] retain = 1

2015-12-17 15:11:23.845内存管理-MRC管理[8484:1270933] retain = 2

2015-12-17 15:11:23.845内存管理-MRC管理[8484:1270933] retain = 1

2015-12-17 15:11:23.846内存管理-MRC管理[8484:1270933]内存已经挂了

Program ended with exit code: 0

 

.m文件实现dealloc

#import"Person.h"
 
@implementation Person
-(void)dealloc{
    NSLog(@"内存已经挂了");
    [superdealloc];
}
@end


内存管理:对象如果不再使用,就应该回收它的空间,防止造成内存泄露

内存管理范围:所有的集成了NSObject的对象内存管理

基本数据类型的数据内存不需要手动进行管理

内存管理原则:

计算机生成了可选文字:只 要 还 有 人 在 使 用 某 个 对 象 , 那 么 这 个 对 象 就 不 会 被 回 收 只 要 你 想 使 用 这 个 对 象 , 那 么 蕨 应 该 让 这 个 对 象 的 引 用 计 數 器 + 1: 当 你 不 想 使 用 这 个 对 象 时 ” . 应 该 让 对 象 的 引 用 计 数 器 一 . 2 ) 谁 臚 , 谁 re a ( 1) 如 果 你 通 过 alloc , new, copy 来 创 建 了 一 个 对 象 , 那 么 你 就 必 续调 用 release 或 者 autorelease ( 2 ) 不 是 你 创 建 的 就 不 用 你 去 负 贵 3)Eretain, *release 只 要 你 调 用 了 retain, 无 论 这 个 对 象 时 如 何 生 成 的 , 你 都 要 调 用 release

#import<Foundation/Foundation.h>
#import"Dog.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
      
       Dog *bd = [[Dogalloc]init];
       
       Dog *jd = [bdretain];//指向同一个空间
       
       NSLog(@"jd= %ld",[jd retainCount]);//2
       NSLog(@"bd= %ld",[bd retainCount]);//2
       
        //bd需要retain释放两次谁retain谁释放
       [bd release];
       
       [bd release];
    }
    return 0;
}


内存管理研究的内容


1).野指针 1.定义的指针变量没有初始化,2.指向的空间已经释放

2).内存泄露

Person *p ={Person new];

P在栈区

[Person new];堆区

如果栈区的p已经释放掉了,而堆区的空间没有释放,堆区的空间就是释放了

 

#import<Foundation/Foundation.h>
 
#import"Dog.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
       Dog *dg = [Dognew];
       
        [dgrelease];//释放掉之后不能再进行 [dg retain]
        //开启僵尸对象检测后,dg称为野指针,会报错,默认情况下不报错
       [dg eat];
       
       
    }
    return 0;
}


单个对象的野指针问题

计算机生成了可选文字:1222demo New Scheme... Manage Schemes... 10

计算机生成了可选文字:MY Mac Build Debug Test Debug Profile Release Analyze Debug Archive Release Finished running : My Mac Memory Management Runtime Sanitization Logging Debugger Shared Diagnostics e 88 1 ( PROJ TARGE• ption m main.m h Dog.h m Dog.m Dog.h m Dog.m m main.m Products Enable Malloc Scribble Enable Malloc Guard Edges Enable Zomb7e Objects Enable Address Sanitizer Requires recompilation Distributed Objects Malloc Stack Log Dynamic Linker API Usage Log Library Loads Stop on Debugger() and Debugstr() Close e Fltcr

再次运行就报错

 计算机生成了可选文字:Zero KB's Zero KB's hread I O _forwarding_ 1 _forwarding_prep_... 2 main 3 start 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 øx7fffgø173544 «+724x callq øx7fffgø173549 «+729* movq øx7fffgø17354c «+732* leaq deallocated instance øx7fffgø2c1a76 %rax, %rcx %rsi $øx3, *edi %eax, %eax %rbx, %rdx %r12, øx7fffgø1bcebø øx7fffgø173662 %r14, %rdi øx7fffgø2c19Ø8 %rax, %rbx %r12, %rdi øx7fffgø2c1a58 %rax, *r 14 %rbx, %rbx øx7fffgø1735b2 %r12, %rbx %rbx, %rdi øx7fffgø2c1a58 %rax, %rsi , symbol stub for: sel_getName —1%s l: message sent to , CFLog , e-lølb Thread 1: EXC_BREAKPOINT subcode-oxO) øx7fffgø173553 øx7fffgø173558 øx7fffgø17355a øx7fffgø17355d øx7fffgø17356ø øx7fffgø173565 øx7fffgø173566 øx7fffgø17356b øx7fffgø17356e øx7fffgø173573 øx7fffgø173576 øx7fffgø173579 øx7fffgø17357e øx7fffgø173581 øx7fffgø173584 øx7fffgø173586 øx7fffgø173589 øx7fffgø17358c øx7fffgø173591 øx7fffgø173594 class su erclass «Z+746* «Z+749* 75 : 757 : «+758-p: «+763x 4+-766* 771 : 77 : 4+-785* 4+-796* movl xo rl movq movq cal Iq int3 j mp movq cal Iq movq movq cal Iq movq testq j ne movq movq cal Iq movq leaq , symbol stub for: , symbol stub for: , symbol stub for: class_getSuperclass object_getClassName object_getClassName NSForwarding: warning: object of does not implement methodSignatureForSelector: — did you forget to declare the of ' O _forwarding_ 2ø15-12-17 2ø15-12-17 -1 Dog eat): message sent to deal Located instance exIøø2øø33ø (Udb)

计算机生成了可选文字:*+ni18NilANULLffJIXYA: • A null pointer to an Objective-C object. nil Nil: A null pointer to an Objective-C class. ( #define nil ((id)O) ) NULL: A null pointer to anything else. ( #define NULL ((void *)O) ) NSNull: A class defines a singleton object used to represent null values in collection objects (which don't allow nil values). ENSNull null): The singleton instance of NSNull.

#import<Foundation/Foundation.h>
#import"Dog.h"
void test(){
    Dog *dg = [Dog new];
    [dg release];
    //nil给 nil发送任何消息都没有效果
    dg = nil ;
    //避免了使用将是对象的方法,对象释放了以后,给对象赋值为nil
    [dg retain];
    
}
int main(intargc,const char* argv[]) {
    @autoreleasepool {
      
       //泄露情况1:没有release的对象一定是泄露的
       //Dog*dg = [Dog new];
      
       //内存泄露情况2没有遵守谁retain谁 release
        //少一次都会造成内存泄露
       Dog *dg = [Dognew];
       [dg retain];
       [dg release];
       
       
        //内存泄露的情况3
        //不当的使用nil
        Dog *dg2 = [Dog new];
       dg2 = nil;
       [dg2 eat];
       [dg2 release];
       
       
        //第四种情况调用的方法中多retain了一次
       Dog *dg3 = [Dognew];
        [dg3 compareColorWithOther:dg3];
       [dg3 release];
       
    }
    return 0;
}

//让对象的引入金属器 +1
#import"Dog.h"
@implementation Dog
-(void)eat{
    NSLog(@"汪星人正在享受午餐");
}
-(BOOL)compareColorWithOther:(Dog *)dog{
 
    [dog retain];//让对象的引入金属器+1
    return YES;
}
-(void)dealloc{
    NSLog(@"Dog类已经释放");
    [superdealloc];
}
@end


多个对象野指针的问题

#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
       Person *p = [Personnew];
       Car *byd = [Carnew];
       byd.speed = 102;
       [p setCar:byd];
       
        [bydrelease];//如果Car对象已经销毁,p成了野指针
        //调用出现严重的报错
        [p goLasa];
    }
    return 0;
}

#import<Foundation/Foundation.h>
#import"Car.h"
@interface Person :NSObject
{
    Car *_car;
    
}
-(void)goLasa;
-(void)setCar:(Car*)car;
@end
 
#import"Person.h"
 
@implementation Person
-(void)setCar:(Car*)car{
    _car = car;
}
-(void)dealloc{
    NSLog(@"Person对象销毁");
    [superdealloc];
}
-(void)goLasa{
    [_carrun];
}
 
@end

#import<Foundation/Foundation.h>
 
@interface Car :NSObject
{
    int _speed;
}
-(void)setSpeed:(int)speed;
-(void)run;
@end

 
#import"Car.h"
 
@implementation Car
-(void)dealloc{
   NSLog(@"车类释放");
    [superdealloc];
}
-(void)setSpeed:(int)speed{
    _speed = speed;
}
-(void)run{
    
    NSLog(@"凤姐开着以%d码的速度往拉萨开qu1",_speed);
}
@end


多个对象内存泄露的问题

#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
       Person *p = [Personnew];
       Car *byd = [Carnew];
       byd.speed = 102;
       [p setCar:byd];
    
       [byd release];
 
       [p goLasa];
       [p goLasa];
       [p goLasa];
       [p goLasa];
       //
        
       [p release];
     
 
    }
    return 0;
}

#import"Person.h"
 
@implementation Person
-(void)setCar:(Car*)car{
    _car = [car retain];//retain
}
-(void)dealloc{
    
    [_cardealloc];//先销毁车子,再销毁人的类
    NSLog(@"Person对象销毁");
    [superdealloc];
}
-(void)goLasa{
    [_carrun];
}
 
@end


原对象无法释放的问题

计算机生成了可选文字:2 ) 00 类 型 (void) setCar:(Car *)car //1. 先 判 断 是 不 是 新 传 进 来 的 对 象 ilf(car!-_car) / / 2 对 旧 对 象 做 一 次 release Lcar releas ; / / 若 没 有 旧 对 象 , 则 没 有 影 响 / / 3 · 对 新 对 象 做一 次 retain car—Icar retain) ; 0

#import"Person.h"
 
@implementation Person
-(void)setCar:(Car*)car{
    //如果是同一个对象就不需要再release再retain一次
    if(_car !=car){
    [_carrelease];//release旧值
   _car = [carretain];//retain新值
    }
}
-(void)dealloc{
    
    [_cardealloc];//先销毁车子,再销毁人的类
    NSLog(@"Person对象销毁");
    [superdealloc];
}
-(void)goLasa{
    [_carrun];
}
 
@end

set方法内存管理原则

原则:如果一个类中,有其他类的对象(关联关系)

set方法书写的时候,要判断是否同一个对象,release

 

@property参数

计算机生成了可选文字:atomic nonatomic readwrite readonly assi n retain copy setter ,


数据库事务处理

当存钱的事务没有完成的时候,另外一边没办法取钱的。就是原子性

数据回滚

Nonatomic不涉及多线程的情况下,不考虑安全的情况下高性能,一般使用这个

Atomic低性能默认


内存管理相关参数

Retain 在类中有关联其他对象的时候,@property(nomatic,retain)这个对象需要retain,先release原来的值,然后再retain新值(在set方法内部进行新对象和旧对象是否相同的判断,

新对象则release,再retain)

Assign 直接赋值,没有进行retain操作 ,实例变量是基本数据类型的时候,或者不写(默认值)

Copy  :先release再copy新值

 

#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
       
       Person *p = [Personnew];
       [p isVip:YES];
       if (p.isVip){
          NSLog(@"是vip客户");
       }
       
       
    }
    return 0;
}
 
 
#import<Foundation/Foundation.h>
 
@interface Person :NSObject
@property (nonatomic,assign,setter=isVip:,getter=isVip)BOOL  vip;
@end
 
#import<Foundation/Foundation.h>
#import"Seller.h"
#import"Buyer.h"
#import"Goods.h"
#import"Person.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
       Person *person = [Person new];
       [person release];
 
       Buyer *buyer = [Buyer new];
       [buyer release];
       
       Goods *goods = [Goods new]; //1
       Seller *seller = [Seller new];//1
       seller.good = goods;//2
       
       [goods release];//1
       [seller release];
     
    }
    return 0;
}
 
 
#import<Foundation/Foundation.h>
typedef  struct Time{
    int minute   ;
    int hour;
    int second ;
    
}myTime;
typedef  struct Date{
    int year   ;
    int month ;
    int day ;
    myTime time;
    
}myDate;
 
@interface Goods :NSObject
@property(nonatomic,assign)float productPrice;
@property(nonatomic,assign)float weight;
@property(nonatomic,retain)NSString *productName;
@property(nonatomic,retain)NSString *productImage;
@property(nonatomic,assign)myDate productDate;
@property(nonatomic,assign)myDate expireDate;
@end
 
 
#import"Goods.h"
 
@implementation Goods
-(void)dealloc{
    [_productNamerelease];
    [_productImagerelease];
    NSLog(@"Goods释放");
    [superdealloc];
    
}
@end
 
#import<Foundation/Foundation.h>
typedefenumsex{KSexFemale,KSexMale,KSexRY} iSex;
@interface Person :NSObject
@property (nonatomic,retain)NSString *name;
@property (nonatomic,assign)iSex sex;
@property (nonatomic,assign)int age ;
@property (nonatomic,assign)float weight;
@end
 
#import"Person.h"
 
@implementation Person
-(void)dealloc{
    [_namerelease];
    NSLog(@"Person释放");
    [superdealloc];
}
@end
 
 
#import"Person.h"
 
@interface Buyer :Person
 
@end

#import"Buyer.h"
 
@implementation Buyer
-(void)dealloc{
    
    NSLog(@"BUyer释放");
    [superdealloc];
}
@end
 
#import"Person.h"
#import"Goods.h"
@interface Seller :Person
@property(nonatomic,retain)Goods *good;
@end

#import"Seller.h"
 
@implementation Seller
-(void)dealloc{
    [_goodrelease];
    [superdealloc];
}
@end


 计算机生成了可选文字:1) # imp 。 rt 方 式 会 包 含 被 引 用 类 的 质 有 亻 訁 息 , 包 括 被 引 用 类 的 变 量 和 方 法 靄 lass 方 式 只 是 告 诉 编 译 器 在 A h 文 件 中 B *b 只 是 类 的 声 明 , 具 体 这 个 类 里 有 什 么 信 息 , 这 里 不 需 要 知 道 , 等 实 现 文 件 中 真 正 要 用 到 时 , 才 会 真 正 去 查 看 B 类 中 信 息 ; 2 ) 使 用 lass 方 式 由 于 只 需 要 只 要 被 引 用 类 (B 类 ) 的 名 称 就 可 以 了 , 而 在 实 现 类 由 于 要 用 到 被 引 用 类 中 的 实 体 变 量 和 方 法 , 所 以 需 要 使 用 # im “ rt 来 包 含 被 引 用 类 的 头 文 件 3 ) 通 过 上 面 2 点 也 很 容 易 知 道 在 编 译 效 率 上 , 如 果 有 上 百 个 头 文 件 都 # imp 。 rt 了 同 一 个 文 件 , 或 者 这 些 文 件 依 次 被 #improt (A-)B, B 一 〉 C,C 一 〉 D . “ ), 一 旦 最 开 始 的 头 文 件 稍 有 改 动 , 后 面 引 用 到 这 个 文 件 的 所 有 类 都 需 要 新 译 一 邊 , 这 样 的 效 率 也 是 可 想 而 知 的 , 而 相 对 来 讲 , 使 用 靄 lass 方 式 就 不 会 出 现 这 种 问 题 了

#import可能出现重复引入的问题,A类引入B类头文件,B类引入A类头文件,循环引入问题

@class可以解决这个问题。

 

#import作用:把要引入的头文件拷贝到#import

如果某个.h文件发生变化

@class类名;

.m文件中导入 person.h头文件,运行时候检查,效率提升一半, 告诉编译器她的属性和方法

 

@class即便你的类变化了,也不会重新编译

如果xxx文件内容发生了改变,而不需要重新编译

 
#import<Foundation/Foundation.h>
#import"A.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
      
       A *a = [Anew];
       [a test];
    }
    return 0;
}
 
#import<Foundation/Foundation.h>
 
@interface Person :NSObject
@property (nonatomic,assign)int age;
 
@end
 
 
#import"Person.h"
 
@implementation Person
@end
 
#import<Foundation/Foundation.h>
@classPerson;
@interface A :NSObject{
    Person *_person;
}
-(void)test;
@end
 
#import"A.h"
#import"Person.h"
@implementation A
-(void)test{
    _person = [Personnew];//需要实例化一次
    _person.age =10 ;
    NSLog(@"Person age =%d",_person.age);
}
@end


循环retain问题set方法给retain了一次

使用@class解决循环引用的问题

1.让某个对象多释放一次 (注意顺序)

2.其中一端设置为assign

 
#import<Foundation/Foundation.h>
#import"Dog.h"
#import"Person.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
      
       Person *p = [Personnew];
       Dog *d = [Dognew];
       
       
       p.dog = d ;//2
       d.owner = p ;//2
        //retain + 1 @peoperty参数为 retain
        //循环引用导致内存泄露
       //
       
       [p release];
       
       [d release];
       
        //释放一次之后,p对象指向d d对象指向p
       
        //[drelease];//0
       /*
        objc[22430]: Person object 0x100103970 overreleased whilealready deallocating; break on objc_overrelease_during_dealloc_error to debug
        */
    }
    return 0;
}
 
#import<Foundation/Foundation.h>
//人拥有一条狗
@classDog;
@interface Person :NSObject
@property(nonatomic,retain)Dog *dog;
@end
 
 
#import"Person.h"
#import"Dog.h"
@implementation Person
-(void)dealloc{
    [_dogrelease];
    NSLog(@"Person对象已经释放");
    [superdealloc];
}
@end
 
#import<Foundation/Foundation.h>
@classPerson;
@interface Dog :NSObject
@property (nonatomic,assign)Person *owner;
@end
 
#import"Dog.h"
#import"Person.h"
@implementation Dog
-(void)dealloc{
   // [_ownerrelease ];
    NSLog(@"Dog对象已经释放掉");
    [super dealloc];
}
@end

1.p.dog  =d ; //此时drc值为2

d并没有真的释放

计算机生成了可选文字:Person Person new (Dog new Dog p. dog —d , 2 // d. owner —p; // retain + 1 epeoperty'üh retain Cd release) ; (p release);

 d对象为rc = 1

计算机生成了可选文字:

    _dog对象的地址值变为nil 


2.d.owner =p ; //此时prc值为2

计算机生成了可选文字:(Person Person *d (Dog new Dog do new 2 retain // retain + 1 Cd release) ; (p release) ; epeoperty

计算机生成了可选文字:WZXOzuauMO 061'J-Sop-

计算机生成了可选文字:p.dog d owner—Ox280 _dog-C.•190

Release一次之后两个局部对象都没有了,内存堆区对象互相指向,如下结果,对象为rc都为1

计算机生成了可选文字:p.dog d owner—Ox280 ox280 _dogzOx190

计算机生成了可选文字:Person Person new (Dog new Dog p. dog —d , 2 d. owner —p; // retain + 1 epeoperty'üh retain Cd (p release) ; release) ;

计算机生成了可选文字:Person Person new (Dog new Dog p. dog —d , 2 d. owner —p; // retain + 1 epeoperty'üh retain Cd (p (p release) ; release) ; release)

prelease一次,_dog对象指向d_dog先释放,指向的_owner对象也要释放,d的rc值变为0,

计算机生成了可选文字:" wn03u 051 0 鬥

objc[22690]: Person object 0x100201450 overreleasedwhile already deallocating; break on objc_overrelease_during_dealloc_error todebug

2015-12-28 18:28:48.631 retain循环使用[22690:2709503] Dog对象已经释放掉

2015-12-28 18:28:48.632 retain循环使用[22690:2709503] Person对象已经释放

Program ended with exit code: 0

 

栈区地址最高

计算机生成了可选文字:

 

定义的字符串,字符串是在常量区,如果你的字符串在常量池已经存在,不会分配内存空间

stringWithString

[NSStringalloc] initWithString

NSString *str =@"abc";

在常量区


stringWithFormat是在堆区

堆区不需要释放,没有alloc也不用释放

[NSStringalloc]initWithFormat最好是release一次


尽量不要使用retainCount这个方法,自己创建的对象这么判断是没错的,但是像OCfoundation框架下的对象,用这样的方法判断,可能不准确,

计算机生成了可选文字:rmat : @'aaa" Using 'stringWithString:' with a literal is redundant : ret retainCount. st r2 Quick Help Declaration — (NSUInteger) retainCount Description Do not use this method. The receiver's reference count. This method is 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. To understand the fundamental rules of memory management that you must abide by, read Memory Management Policy. To diagnose memory management problems, use a suitable tool: The Clang Static analyzer can typically find memory management problems even before you run snour program. The Object Alloc instrument in the nstruments application (see Instruments User tr3. tr4. tr5. tr6. re aln oun retainCount retainCount_) retainCount•

int main(intargc,const char* argv[]) {
    @autoreleasepool {
       
       NSString *str1 = @"abc";
        NSString *str2 = [NSString stringWithFormat:@"aaa"];
        NSString*str3 = [NSStringstringWithString:@"abc"];//字符串常量池
        NSString *str4 = [[NSString alloc] initWithFormat:@"aaa"];
        NSString *str5 = [[NSString alloc] initWithString:@"abc"];
        NSString *str6 = [[NSString alloc] init];
        //str6赋了值就存在常量区
       int a = 10;//在栈区
       
       
       NSLog(@"str1= %@,%p,%lu",str1,str1,str1.retainCount);
       NSLog(@"str2= %@,%p,%lu",str2,str2,[str2retainCount]);
       NSLog(@"str3= %@,%p,%lu",str3,str3,str3.retainCount);
       NSLog(@"str4= %@,%p,%lu",str4,str4,str4.retainCount);
       NSLog(@"str5= %@,%p,%lu",str5,str5,str5.retainCount);
       NSLog(@"str6= %@,%p,%lu",str6,str6,str6.retainCount);
       NSLog(@"%p",&a);
       
       
 
    }
    return 0;
}

2015-12-28 19:30:59.229 NSString类的内存管理问题[22960:2750176] str1 =abc,0x100001030,18446744073709551615

2015-12-28 19:30:59.231 NSString类的内存管理问题[22960:2750176] str2 =aaa,0x61616135,18446744073709551615

2015-12-28 19:30:59.231 NSString类的内存管理问题[22960:2750176] str3 =abc,0x100001030,18446744073709551615

2015-12-28 19:30:59.231 NSString类的内存管理问题[22960:2750176] str4 =aaa,0x61616135,18446744073709551615

2015-12-28 19:30:59.232 NSString类的内存管理问题[22960:2750176] str5 =abc,0x100001030,18446744073709551615

2015-12-28 19:30:59.232 NSString类的内存管理问题[22960:2750176] str6 =,0x7fff77267d20,18446744073709551615

2015-12-28 19:30:59.232 NSString类的内存管理问题[22960:2750176] 0x7fff5fbff70c

Program ended with exit code: 0

 

%d可能是 -1

常量区的引入器是一个无符号数的最大值

 

对象的”autorelease”方法代替”relrease”方法可以延长它的生命周期,直接到当前”AutorelreasePool”释放。如果想让此对象的生命周期超过”Autorelease Pool”,还可以再次”retain”,呵呵,有意思吧〜且让我慢慢道来。


Autoreleasepool基本使用

是一种支持引用计数器的内存管理方式

它既可以暂时保存某个对象,然后在内存池自己的排干(drain)的时候对其中的每个对象发送release消息

注意:这里只是发送release消息,如果当时的rc依然部位0,则对象不会释放,可以用该方法来保存某个对象,也要注意保存之后要释放该对象

 

使用autorelease的好处

1.不需要关系对象的释放时间

2.不需要再关系什么时候调用release

计算机生成了可选文字:MfiAutorelease pool#l, orelease pool*", 1) pool *Tautorelease pool retain release autorelease drain etain—

#import<Foundation/Foundation.h>
#import"Person.h"
int main(intargc,const char* argv[]) {
    Person *p = [Person new];
    
    @autoreleasepool {
       
       [p run];
        NSLog(@"%lu",p.retainCount);
       
        [pautorelease];//把对象p加入到自动释放池
        // 注意:加入到自动释放池,引入计数器不会变化
        NSLog(@"%lu",p.retainCount);
       
       [p run];
       
    }
    
    //@autoreleasepool结束的时候调用了 release
   
    [p run];
    /*
    *** -[Person run]: message sent to deallocated instance 0x100203e30
    (lldb)
    */
    return 0;
}


为什么内存管理只管理oc对象

堆区内存不连续,无法自动释放

堆区通过链表来实现的,链表是指针将内存里物理上不连续的逻辑单元内存单元进行逻辑上的连续


Autorelease注意及错误用法

autorelease将对象的释放延迟

#import<Foundation/Foundation.h>
#import"Person.h"
void test(){
    //3.只需要在自动释放吃中调用autorelease,就可以把对象加入到自动释放池
    Person *p = [Personnew] ;
    @autoreleasepool {
       
       
        //Person *p = [[Person new] autorelease];
        //1)并不是所有的放到自动释放吃中的代码,产生的对象就会自动释放
        //如果需要释放,必须加入到自动释放池
       
       
       //3.接3
       [p autorelease];
       
       
    }
    //2.如果对象调用autorelease,不在自动释放池中,不会被释放
    //Person*p = [[Person new] autorelease];
 
}
 
void test2(){
    Person *p = [Personnew] ;
    
    //@autoreleasepool嵌套
    //自动释放池以栈的结构存储
    //栈顶先进后出对象存在位于栈顶位置的自动释放池中
    @autoreleasepool {
        @autoreleasepool {
           
            @autoreleasepool {
               
               //同一个对象不要在一个autoreleasepool中autorelease两次
              //会发两次消息,登记两次
               //不要将循环操作放入到自动释放池中,对象是延迟销毁的,可能造成内存负担
               [p autorelease];
               
           }
           
       }
       
       
    }
    
 
}
int main(intargc,const char* argv[]) {
    
    Person *p = [Personnew] ;
    
    @autoreleasepool {
       //错误用法3
       [p autorelease];
       
    }
    [p release];
    /*
    Person object 0x100300050 overreleased while already deallocating; breakon objc_overrelease_during_dealloc_error to debug
    Program ended with exit code: 0ß
    */
 
    return 0;
}
 

#import<Foundation/Foundation.h>
#import"Person.h"
#import"Student.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
       //快速创建对象
       Person *p = [Personperson];//person是一个类方法
       NSArray *nsa = [NSArray array];
        //+(instancetype)array;
        NSDictionary *nsd = [NSDictionary dictionary];
        //+(instancetype)dictionary;
       
        //动态类型程序直到运行的时候才知道这个对象属于什么类型
       Student *stu = [Student person];
        //2015-12-29 03:10:42.450 autorelease应用场景[24020:2886223] person run
       [stu run];
        //因为stu释放的时候调用的[super dealloc]父类是Person
        //然后Person又调用一次 [super dealloc]
        //所以打印两次 Person dealloc
       
       //存在问题
       NSString *str1 = [Student person];
       
       // 如果是instancetype可以智能的判断赋值的指针变量的类型和返回值的类型是否一致
        //id 不会存在警告
       
       
    }
    return 0;
}
 
#import<Foundation/Foundation.h>
 
@interface Person :NSObject
//将id改为 instancetype
+(instancetype)person;
-(void)run;
@end
 
#import"Person.h"
 
@implementation Person
-(void)dealloc{
    NSLog(@"Persondealloc");
    [superdealloc];
}
-(void)run{
    NSLog(@"person run");
}
+(instancetype)person{
    
    
    
    return [[[selfalloc]init ]autorelease];//返回的是一个对象空间
    
}
@end
 
#import"Person.h"
 
@interface Student :Person
 
@end
 
 
#import"Student.h"
 
@implementation Student
-(void)run{
    NSLog(@"Studentrun");
}
-(void)dealloc{
    NSLog(@"Studentdealloc");
    [superdealloc];
}
@end
 
 
如果返回值是一个对象,必须使用instancetype
 
 
创建一个学生类并初始化年龄,快速创建的构造方法
#import<Foundation/Foundation.h>
#import"Student.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
       //Student *stu = [[Student alloc] initWithAge:30];
        //NSLog(@"stu.age=%d",stu.age);
        //[sturelease];
       
       
        Student *stu = [Student studentWithAge:30];
       NSLog(@"stu.age= %d",stu.age);
       
    }
    return 0;
}
 
#import<Foundation/Foundation.h>
 
@interface Student :NSObject
@property(nonatomic,assign)int age;
 
-(instancetype)initWithAge:(int)age;
 
+(instancetype)studentWithAge:(int)age;
@end
 
#import"Student.h"
 
@implementation Student
-(instancetype)initWithAge:(int)age{
    //先初始化父类的,并且判断是否初始化成功
    if(self = [superinit]){
    
    //初始化子类的
       _age = age ;
    }
    //返回sefl
    return self;
    
}
 
+(instancetype)studentWithAge:(int)age{
    return [[[self alloc]initWithAge:age] autorelease];
}
-(void)dealloc{
    NSLog(@"Studentrelease");
    [superdealloc];
}
@end


默认情况下,所有指针都是强指针,关键字strong

弱指针,__weak关键字修饰


Arcautomaticreferencecounting自动引入计数,解决了手动内存管理的麻烦


不需要写retain,release,autorelease

三个关键字

机制:

arc是在代码编译的时候,为你在核实的位置插入relese,autorelease


判断准则:

arc只要没有强指针指向对象,对象就会被释放

注意:arc的时候,没有引入计数器,会报错,

 

当两个对象存在包含关系时,对象1有一个strong指针,并持有他,而对象中有一个weak指针指回对象1,避免了对象循环持有。

弱指针指向的话,先释放然后将weak指针指向nil

 

arc机制判断

Arc下可以调用dealloc方法,不能调用父类的dealloc方法


arc下但对象的内存管理,不是运行时特性或者垃圾回收机制。

编译的时候,自动加入release,autorelease

#import<Foundation/Foundation.h>
#import"Car.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
      
       Car *car = [Carnew];
       
       __strongCar *bwm = car;//指针默认都是强指针
       __weak Car*bz = car ;
        car =nil;//对象销毁
        //让car的指向发生改变,对于car对象来说,没有强指针指向,所以释放对象
        //弱指针指向的对象如果被释放,*bz弱指针,自动被赋值为nil
       
       [car run];
       
       
    }
    return 0;
}

只要给对象赋值nil,自动会释放,nil执行任何方法都不会报错


ARC多对象内存管理

#import<Foundation/Foundation.h>
#import"Person.h"
#import"Dog.h"
int main(intargc,const char* argv[]) {
    @autoreleasepool {
       
       Dog *jd = [Dognew];
       
       
       
       Person *p = [Personnew];
       
       p.dog = jd ;
       
       // jd = nil ;//在@property下 week指针 dog会立即释放,因为对象没有强指针对象了
       
        //jd = nil ;//在@property下 strong指针 jd释放掉之后 _dog指向Dog对象
        //先释放Person再释放Dog
       
    
    }
    return 0;
}

计算机生成了可选文字:9 10 11 12 13 14 015 16 17 18 19 20 21 22 #import «Foundation/Foundation. #import "Dog. h" #import "Person. h" int main(int argc, const char * argvll) cautoreleasepool *dog — Dog Dog new (Person new) ; Person return with exit ø; code: ø : 31375381 : 31375381 : 31375381 xxxx Person Dealloc Dog deal loc 2ø15-12-29 2ø15-12-29 2ø15-12-29 Program ended

互相关联的时候,strong类型指针,结束时候无法释放内存

计算机生成了可选文字:9 10 11 12 13 14 15 16 17 18 19 20 21 22 #import •oundation/Foundation. #import "Dog. h" #import "Person. h" int main(int argc, const char * argvll) cautoreleasepool *dog — Dog Dog new (Person new) ; Person p. dog dog ; dog. owner return ø; xxxx code: ø 2ø15-12-29 Program ended with exit

栈区释放之后pdog对象释放

但是 _dog _owner对象没有释放

 计算机生成了可选文字:#import •oundation/Foundation. cc lass Person• @interface Dog . NSObject ep rope rty ( nonatom ic , weak) Person *owner ; cend

计算机生成了可选文字:9 10 11 12 13 14 15 16 17 18 19 20 21 22 #import •oundation/Foundation. #import "Dog. h" #import "Person. h" int main(int argc, const char * argvll) cautoreleasepool *dog — Dog Dog new Person (Person new) ; p, dog dog ; dog. owner return with exit ø; code: ø • 315855øl • 3158550 3158550 xxxx Person Dealloc Dog deal loc 2ø15-12-29 2ø15-12-29 2ø15-12-29 Program ended

将一端设置为弱指针


下方的Dog对象没有强指针指向,所以先释放 ,

计算机生成了可选文字:Person _dogz 0000 Dog _owne

计算机生成了可选文字:_dogz

所以_owner也没有了

接着就是指向Person对象强指针也消失,所以Person对象释放

计算机生成了可选文字:9 10 11 12 13 14 #import •oundation/Foundation. cc lass Dog; @interface Person : NSObject Dog *dog; cend 2ø15-12-29 xxxx 2ø15-12-29 Dog dealloc 2ø15-12-29 Person Dealloc Program ended with exit code: ø

 

 

 

 

UI控件一般使用弱对象指针

计算机生成了可选文字:ARC Tset ARCE# fi@property strong : weak : assign : copy : —RfiTNSString, @property weak

arc的使用特点和注意事项


计算机生成了可选文字:1 、 ARC 特 点 总 结 ( 1) 不 允 许 调 用 release, retain, retainCount ( 2 ) 允 许 重 写 dealloc, 但 是 不 允 许 调 用 (super deallocJ ( 3 ) @property的 参 数 : strong:*E 当 于 原 来 的 retain ( 适 用 于 对 象 类 型 ) , 成 员 变 量 是 强 指 针 weak:*E 当 于 原 来 的 assign, ( 适 用 于 oc 对 象 类 型 ) , 成 员 变 量 是 弱 指 针 assign: 适 用 于 非 对 象 类 型 ( 基 础 类 型 )

 __weakPerson *p1 = [[Personalloc] init];

       /*

         /Users/chingwei_macpc/Documents/内存管理学习/ARC下循环引用问题/main.m:19:24:Assigning retained object to weak variable; object will be released afterassignment

        */

定义完之后立刻销毁,没有意义

-fno-objc-arc

计算机生成了可选文字:Resource Tags Target Dependencies (O items) Compile Sources (4 items) Namc m Person.m m main.m ...in m Student.m ...in Link Binary With Libraries (O items) Copy Files (O items) xxxx Build Settings Build Rules e Filter Compiler Flags -fno-nbjc-arc

将一个mrc转换为arc,convertto objectcarc

计算机生成了可选文字:File ts, OS X ARC*L •son.h •son.m lin.m Edit Vi Undo Redo Cut Copy Paste Special Paste Paste and Preserve Formatting Duplicate Delete Select All Filter Sort Format Refactor Start Dictation... Special Characters... 36 37 38 39 40 Prog ram Produc Debu Source Control Window Hel m ma.n.m running 11- 11- *5MRci$WhARC ) 11- m main.m ) O main() fn fn '*Space (by g) le go asa ; release) ; eng j ie car gjie goLasaJ ; gjie goLasaJ ; gjie goLasaJ ; Rename... Extract... Create Superclass. Move Up... Move Down... Encapsulate... // bmw 1, pers bwm Convert to Objective-C ARC... Convert to Modern 0b' ive-C Syntax. Convert to XCTest... No Selection 2ø15-ø4-3ø 2ø15-ø4-3ø 2ø15-ø4-3ø 15:25: 47.355 ended with exit 11- 11- 11- code: ø

 

计算机生成了可选文字:view changes: 18 18 23 26 m Person.m 2 5 6 8 9 10 11 12 13 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30 Pe rson.m Created by CHINGWEI_MACPC on 15/12/17. Copyright 0 2ø15# itcast. All rights reserved. #import "Person. h" @implementation Person —(void)setCar: (Car if(_car car H car release) ; // release IEfÄ (car retain) ; // retain car —(void)deallocl _car deallocl , NSLog (Q" ; (super deal loc); —(void)goLasaI car run cend o o m Car.m ml main.m Person.m Cancel No Selection 2 5 6 8 9 10 11 12 13 14 15 16 17 19 20 21 22 24 25 27 28 29 Pe rson.m Created by CHINGWEI_MACPC Copyright 0 2ø15# itcast. reserved. #import "Person. h" @implementation Person —(void)setCar: (Car if(_car car H // release car; // retain car — —(void)deallocl NSLog ; —(void)goLasaI I_car runl ; cend on 15/12/17. All rights Save Person.m (Before Conversion) m Person.m (After Conversion) Previous

左边为改动后,


计算机生成了可选文字:set@propertygetm auto release E*k... auto release TH%... Combined Build Options Setting Enable Testability Debug Rel ease Levels Resolved KMuItipIe values* C Resolved Yes (Aggressive) C cMuItipIe values' C Yes v Yes (Aggressive) C os x Default No v OS X Default os x Default Apple LLVM 7.0 - Language - Objective C Setting Objective-C Automatic Reference Counting Apple LLVM 7.0 - Warnings - All languages Setting Uninitialized Variables


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值