内存管理初级

本文深入探讨了iOS开发中的内存管理机制,包括MRC、ARC以及垃圾回收技术的应用。通过实例展示了如何在Objective-C中合理使用引用计数、手动释放和自动释放,同时介绍了内存管理中的一些关键方法和注意事项。此外,还详细解释了垃圾回收的过程以及如何避免常见的内存泄漏问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

// iOS应用程序出现Crash(闪退),90%以上的原因是内存问题。

在一个拥有数十个甚至上百个类的工程里,查找内存问题及其困难。了解内存常见问题,能帮我们减少出错几率。

内存问题体现在两个方面:内存溢出,野指针异常。

垃圾回收:程序员只需要开辟内存空间,不需要用代码显示地释放,系统来判断哪些空间不再被使用,并回收这些内存空间,以便再次分配。整个回收过程不需要写任何代码,有系统自动完成垃圾回收。java开发一直使用的就是垃圾回收技术。

Manual Reference Count(MRC),人工引用计数:内存的开辟和释放都由程序代码进行控制。相对垃圾回收来说,对内存的控制更加灵活,可以在需要释放的时候及时释放,对程序员要求较高,程序员要熟悉内存管理机制。

Auto Reference Count(ARC),自动引用计数:iOS5.0的编译器特性,它允许用户只开辟空间,不需要释放空间。它不是垃圾回收,本质还是MRC,只是编译器帮程序员默认加了释放代码。

ARC是基于MRC。



//  main.m


#import <Foundation/Foundation.h>

#import "Person.h"

#import "Student.h"

 

int main(int argc, const char * argv[]) {

   @autoreleasepool {

         // c语言的内存管理

       //  malloc,realloc,calloc申请堆区内存

       // free 释放堆区内存。

       //  采用垃圾回收机制管理堆区内存。

 

       // oc的内存管理:

       // 采用引用计数进行管理。

       // 主要分为两种:ARC(automatic reference counting)

       // MRC(manual reference counting)

       //  ARC 是 ios5.0之后的语法,也是基于MRC实现的,只不过将程序员本该释放的代码交给了编译器去做。

 

     // 影响引用计数的几个方法

   //  + (id)alloc;

   // 创建对象,堆区分配内存空间

//       Person *p = [[Person alloc]initWithName:@"ylc" age:22];

//   // 打印引用计数

//   //引用计数是堆区对象所特有的。

//   // - (NSInteger)retainCount;

//       // 一般来说不需要返回值

//       [p retain];

//       NSLog(@"%ld",p.retainCount);

 

  //- (id)copy:如果是深拷贝,原对象引用计数不变,新对象引用计数 +1,产生一个新对象

       //如果是浅拷贝(指针拷贝),原引用计数 +1,新对象引用计数等于原对象引用计数,且新旧对象的地址一样。

//  retainCount 打印出来的引用计数永远不可能为0;

//   引用计数从 0 到 1 是申请内存,从 1 到 0 是释放内存。

 

   //  - (id)retain : 引用计数加1

 

        //  浅拷贝

//       Person *p2 = [[Person alloc]initWithName:@"zf" age:666];

//       Person *p3 = [p2 copy];

//       NSLog(@"%p,%p",p2,p3);

//       NSLog(@"%ld %ld",[p2 retainCount],[p3 retainCount]);

//       NSLog(@"%@",p3.name);

//       

 

//        // 深拷贝

//       Person *p4 = [[Person alloc]initWithName:@"呵呵"age:11];

//       [p4 retain];

//       Person *p5 = [p4 mutableCopy];

//       NSLog(@"%ld %ld",p4.retainCount,p5.retainCount);

//       NSLog(@"%p %p",p4,p5);

//       NSLog(@"%@ %@",p4.name,p5.name);

 

//                Student *stu = [[Studentalloc]init];

//               stu.name = @"name";

//                Student *s =  [stu copy];

//                NSLog(@"%@",s.name);

//       

//                s.name = @"Name";

//               NSLog(@"%@",stu.name);

//                NSLog(@"%p%p",stu,s);

//       

//             Student *s1 = [stumutableCopy];

//              NSLog(@"%p %p",stu,s1);

//              s1.name = @"name";

//              NSLog(@"%@%@",s1.name,stu.name);

 

 

       // 释放  - (void)release 引用计数减 1,

//       //Person *p6 = [[Person person]WithName:@"1" age:1]; //不用释放

//       Person *p6 = [[Person alloc]init];

//       Person *p7 = [p6 retain];

//       Person *p8 = p6;

//       [p6 release];

//       [p6 release];

       // 没有alloc,retain,copy 就不需要释放。

 

       // 在同一个大括号内,有增加的地方就需要减少,增加和减少的次数相等,保持所谓的动态平衡。

 

       //对谁 retain 就对谁release。

       // 对谁 copy ,如果是深拷贝那么新旧对象都release

       //  如果是浅拷贝,随便release一个(建议对谁copy,就对谁release)。

 

//       // dealloc

//       Person *p = [[Person alloc]initWithName:@"aa" age:33];

//       NSLog(@"%p",p);

//      // [p release];

//       

//       // autorelease  引用计数减1,延迟释放,至于释放的时间根据自动释放池被摧毁时间而定

//       Person *p1 = [[Person alloc]initWithName:@"a" age:1];

//       [p1 retain];

//       NSLog(@"%ld",[p1 retainCount]);

//        

//       // 向对象发送autorelease消息,对象引用不会立即减少

//       // 向p,p1发送autorelease消息,其实是将对象加入自动释放池,当自动释放池,当自动释放池被销毁时,逐一向对象发送release消息。自动释放池以栈的形式管理对象,先进去后销毁,后进去先销毁。

//       [p autorelease];

//       [p1 autorelease];

//       [p1 autorelease];

//        NSLog(@"%ld",p1.retainCount);

//        NSLog(@"%p",p1);

 

       //6 字符串的拷贝

          //在常量区

       // 采用字面量对字符串进行初始化,引用计数用%lu打印为无符号长整形最大数,如果用%ld打印为 -1.

       //  常量区的字符串,不管是汉字还是其它字符,%ld 输出的retaincount都为 -1.

       // 而用 Format创建的字符串,当字符串是汉字时,%ld 输出的retainCount 为 1,er其他字符只有当 length超过 9 后才输出1.

       // 当 retainCount 为 -1 时,retain 不会增加引用计数的次数。

//       NSString *s = @"wqeqererewrere";

//      // s1当字符超过9个是,%ld输出 S1.retainCount 为1,否则为 -1.

//       

//       NSString *s1 = [[NSString alloc]initWithFormat:@"123456789"];

//       NSLog(@"s1 = %p",s1);

//       NSLog(@"s = %p",s);

//       NSString *s3 = [s1 retain];

//       NSLog(@"%ld %ld",s.retainCount,s1.retainCount);

 

 

//       // foundation 框架下的大部分分类都遵循了NSCopying,及NSMutableCoping协议,因此我们对框架下的类操作的时候不需要遵循协议了,自定义的类需要遵循协议且实现对应方法。

//       NSString *s = [[NSStringalloc]initWithFormat:@"huaaaaaaaaasfdds"];

//       NSString *s1 = [s copy];

//       NSString *s2 = [s mutableCopy];

//       NSLog(@"%p",s);

//       NSLog(@"%p",s1);

//       NSLog(@"%p",s2);

//       // 字符串唯一的浅拷贝就是不可变字符串的不可变拷贝。 (copy)       

//       [s release];

//       [s1 release];

//       [s2 release];

//       NSMutableString *mstr = [[NSMutableStringalloc]initWithFormat:@"1232434352wwq"];

//       NSMutableString *mstr1 = [mstr copy];

//       NSMutableString *mstr2 = [mstr mutableCopy];

//       NSLog(@"%p",mstr);

//       NSLog(@"%p",mstr1);

//       NSLog(@"%p",mstr2);

//       [mstr release];

//       [mstr1 release];

//       [mstr2 release];

 

    }

 

//    //  之前的自动释放池写法

//   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];

//   Person *p = [[Person alloc]init];

//   // 将对象加入自动释放池

//   [p autorelease];

//   // 将池对象销毁

//   [pool release];

 

 

   return 0;

}

 

 

 

//

//  Person.m


#import "Person.h"

 

@implementation Person

 

// dealloc 用来释放属性对应的实例变量(对象类型)

// 当对象的引用计数从 1 变为 0 的时候会自动向dealloc发送消息。

- (void)dealloc{

   NSLog(@"%@我被释放了",self);

   [_name release];

   [super dealloc];

}

 

    // copy方法的内部实现会调用了copyWithZone

   // 1、浅拷贝(指针拷贝)的实现

- (id)copyWithZone:(NSZone *)zone{

   return [self retain];

}

 

 // 深拷贝的实现

 // 会产生一个新的地址,地址存放的内容和原对象的内容一模一样。

- (id)mutableCopyWithZone:(NSZone *)zone{

   Person *p = [[Person alloc]init];

   p.name = self.name;

   p.age = self.age;

   return p;

 

}

- (instancetype)initWithName:(NSString*)name age:(NSInteger)age{

   if (self = [super init]) {

       _name = name;

       _age = age;

    }

   return self;

}

@end

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值