iOS进阶内存管理内存 数据库,存储 网络缓存

iOS中的内存管理

2016-04-13  本文已影响1602人  少少白

先来看下苹果文档:

memory_management.png

Objective-C提供两种方式的内存管理方式:

内存管理一般出现的问题:

内存管理的基本法则:

去年参加了一个技术分享,讲的是iOS内存管理及优化
引子就很吸引人:

程序员对内存的关注点:

段式虚拟内存的转换过程
段式虚拟内存的转换过程分为两部分:段号和段内偏移.系统有一个全局的段表.先通过段号去段表里查基值和界限,然后加载到基址寄存器和界限寄存器上.然后在经过转换访问物理地址. 页式虚拟内存的访问过程

NSString *str1 = [NSString stringWithString:@"Welcome!"]; //堆分配的内存 Dirty Memory
NSString *str2 = @"Welcome!"; //常量字符串,存放在一个只读数据段里面,这段内存释放后,还可以在读取重建 Clear Memory
char *buf = malloc(100 * 1024 *1024); // Clear Memory分配100M虚拟内存,当没有用时没有建立映射关系
for (int i = 0; i < 3 * 1024 * 1024; ++i) {
buf[i] = rand();
}

     关于Clear Memory和Dirty Memory的介绍 [What is resident and dirty memory of iOS?](http://stackoverflow.com/questions/13437365/what-is-resident-and-dirty-memory-of-ios)   
* Dirty & Resident & Virtual Memory  
    * 虚拟内存层面
        * Virtual Memory = Clear Memory + Dirty Memory   
    * 物理内存层面  
        * Resident Memory = Clean Memory(Loaded in Physical Memory) + Dirty Memory  
    * 物理页面的生命周期   
     根据状态来划分  
       * Free(空闲) 物理页没被任何虚拟内存使用   
       * Active(活跃) 物理页正用于一个虚拟内存页,并且最近被引用过,这种页面一般不会被交换出去  
       * Inactive(非活跃)物理页正用于一个虚拟内存页,但最近没有被引用过,这种页面有可能被交换出去  
       * Speculative(投机) 针对可能的内存需要做了一个猜测的分配,对页面进行投机映射,因为很可能很快被访问到  
       * Wired(联动) 物理页正用于一个虚拟内存页,但不能被交换出去,一般用于内核代码数据  
![物理页面的生命周期](http:https://img.haomeiwen.com/i1736329/5490b505dd10a15b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)   

* 内存的分析工具Allocations   
![Allocations](http:https://img.haomeiwen.com/i1736329/32f9220e8c5f9856.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)   
All Heap & Anonymous VM中All Heap为堆上分配的对象,Anonymous VM比如创建UIView时CALayer底层所占空间.Diry Size为Dirty Memory所占内存,Resident Size为实际所占的物理内存.   

* 内存最佳实践  
   * Weak Strong Dance(解决block循环引用的技巧)  
   AFNetworking中的实践:  
__weak __typeof(self)weakSelf = self;   

AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
}];

可以查看[对Weak String Dance的思考](http://www.jianshu.com/p/4ec18161d790)  
   * Dealloc Block Executor(释放内存的小技巧)  
![Dealloc Block Executor](http:https://img.haomeiwen.com/i1736329/9fa7d457e2a0bd5f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  
AssociateObject的父对象释放的时候,子对象也会被释放.通过block来释放对象,不用使用dealloc.  
![UIView的释放时序图](http:https://img.haomeiwen.com/i1736329/f39d8cf05106499b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    * 降低内存峰值  
       * Lazy Allocation 

MyBuffer *GetGlobalBuffer()
{
static MyBuffer *sMyBuffer = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sMyBuffer = [MyBuffer new];
});
return sMyBuffer;
}

直到使用的时候才分配,且为线程安全,可以用于分配对象或者资源文件读取等,方便Patch,比如JSPatch.
       * alloca VS malloc 
栈内存分配alloca(size_t)
          * 栈分配仅仅修改栈指针寄存器,比malloc遍历并修改空闲列表要快得多  
          * 栈内存一般都已经在物理内存中,不用担心页错误  
          * 函数返回的时候栈分配的空间都会自动释放   
          * 但仅适合小空间的分配,并且函数嵌套不宜过深   
       * calloc VS malloc + memset  
calloc(size_t num,size_t size)分配内存时是虚拟内存,只有在访问的时候才会发生物理页的映射关系,malloc+memset就会产生Dirty Memory.
          * 分配内存并初始化
          * 立即分配虚拟空间并设置清0标记位,但不分配物理内存
          * 只有相应的虚拟地址空间被读写操作的时候才需要分配相应的物理内存页并初始化   
       * AutoreleasePool
          * 基于引用计数,Pool执行drain方法会release所有该Pool中的autorelease对象
          * 可以嵌套多个AutoReleasePool
          * 每个线程并没有设置默认的AutoReleasePool,需要手动创建,避免内存泄露  
          * 在一段内存分配频繁的代码中嵌套AutoReleasePool有利于降低整体内存峰值  
       * imageNamed VS imageWithContentOfFile  
          * imageNamed使用系统缓存,适用于频繁使用的小图片  
          * imageWithContentOfFile不带缓存机制,适用于大图片,使用完就释放
       * NSData with fileMapping
NSData & 内存映射文件,NSData有两种读取方式:
            * [NSData dataWithContentsOfFile:path];
            * [NSData dataWithContentsOfFile:path options:NSDataReadingMappedIfSafe error:&error];映射文件到虚拟内存,只有读取操作的时候才会读取相应页的内容到物理内存页中,常用语大文件中.
    * NSCache & NSPurgableData
        * NSCache 
            * 2种界限条件:totalCostLimt & countLimit 超过这两种界限时都会去释放一些旧的资源.
            * 类NSMutableDictionary,setObject:forKey:cost
            * evictsObjectWithDiscardContent & <NSDicardableContent>
            * 最好监听内存警告消息并移除所有Cache
        * NSPurgableData
            * 当系统处于低内存的时候自动移除
            * 适用于大数据
     * 内存警告的处理
         * 尽可能释放多资源,尤其图片等占内存多的资源,等需要用的时候再重建
         * 单例对象不要创建之后就一直持有数据,在内存紧张的时候释放掉
         * iOS6之后系统内存紧张会自动释放CALayer的CABackingStore对象,需要使用的时候在调用drewRect来构建,所以没必要将self.view = nil,但有时候对于隐藏的ViewController直接设置self.view = nil能简化代码逻辑  
示例代码: 
 

@interface ViewController ()
@property (strong,readonly)NSString testData;
@end
@implementation ViewController
@synthesize testData=_testData;
// Override the default getter for testData
-(NSString
)testData
{
if(nil==_testData)
_testData=[self createSomeData];
return _testData;
}

   * 业内趋势
        * 内存压缩
        * 地址空间布局随机化ASLR
上一篇 下一篇

猜你喜欢

热点阅读