Object-C使用类静态方法创建对象时容易内存泄露

1.所谓使用类的静态方法创建对象,就是指使用类名调用一次它的静态方法(非显式调用alloc)便可以得到一个新建的对象,比如下面两个例子:

  NSString* str1 = [NSString stringWithString:@"hello world"];

  NSMutableString* str2 = [NSMutableString stringWithString:@"hello world"];

2. 第一个例子是使用字符串的字面常量"hello world"创建一个NSString对象,已知常量在编译期分配,存放在程序的数据区(常量区),全局唯一且不可改变;因为NSString对象是不可变的,所以str1直接指向数据区的"hello world",而不会在内存中创建副本;而str2是可变的字符串对象,因此需要将常量“hello world”的内容拷贝到内存,这样才支持对字符串内容的修改。因此,str1的创建基本上不增加内存开销,而str2的创建会增加内存开销。注意,如果以[NSString stringWithFormat:@"hello world %d",i]这种方式创建字符串对象,则也需要增加内存拷贝,他先把常量"hello world %d"拷贝到内存,然后替换掉%d,然后赋给新建的字符串对象。

3.NSString的静态方法stringWithString会创建一个对象,为了保证该对象能够被正确释放,在返回该对象之前,会调用对象的autorelease方法,将对象的释放操作交给了外层的自动释放池对象;而对应的经典的alloc+init方式创建的对象,不会调用autorelease.因为当你显式使用alloc时,ARC会给你添加相应的release操作,所以这种方式创建的对象可以被正常释放。

4.内存泄露的例子

while(YES)
{
        NSMutableString* str = [NSMutableString stringWithString:@"hello world"];  
}

使用死循环是为了使泄露的结果更更显,如果每次操作的数据很大,那效果更明显。

5.泄露的原因

 每次创建对象str,都会开辟一块新内存存放数据"hello world";而释放的方式是autorelease,然而在此循环中接触不到外层的自动释放池,因此所有创建的对象都没有被及时释放掉,因此内存占用会越来越大,效果如同内存泄露。

6.解决方式

一:循环内使用自动释放池,及时释放掉对象(不推荐,增加自动释放池对象创建和销毁开销)

while(YES)
{
      @autorelease{  
        NSMutableString* str = [NSMutableString stringWithString:@"hello world"];  
      }
}

二:使用经典的alloc+init方式创建对象(推荐,效率高而无副作用)

while(YES)
{
        NSMutableString* str = [[NSMutableString alloc]initWithString:@"hello world"];  
}

三:如果可能,使用NSString代替NSMutableString(不推荐,勉强规避)

while(YES)
{
        NSString* str = [NSString stringWithString:@"hello world"];  
}
原文地址:https://www.cnblogs.com/guoxiaoqian/p/4394487.html