zoukankan      html  css  js  c++  java
  • 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"];  
    }
  • 相关阅读:
    JMM、asifserial语义、happensbefore模型
    jvm内存溢出实践
    垃圾回收和GC算法
    jvm运行时数据区域
    实现加锁的消费者和生产者模型
    jvm监控工具小结
    HotSpot对象
    java常用垃圾收集器
    字面量, 符号引用与直接引用
    常用线程安全的队列
  • 原文地址:https://www.cnblogs.com/guoxiaoqian/p/4394487.html
Copyright © 2011-2022 走看看