内存分析
主要目的就是为了检测程序是否存在内存泄露
1. 静态内存分析(Analyze)
作用(可检出下述错误):
> 逻辑错误:访问未初始化的变量, 野指针等;
> 声明错误:从未使用过的对象;
> 内存管理错误:如内存泄漏等;
分析方法:
> 静态内存分析是不运行程序,直接对代码进行分析.
> 根据代码的上下文的语法结构,来分析是否有内存泄露
缺点:
> 不一定准确,但是如果发现有提示,那么去结合上下文看一下,这里的代码是否有问题
// 测试不准确的情况
NSObject *obj = [self obj];
NSLog(@"%@", obj);
[obj release];
- (id)obj {
return [[NSObject alloc] init]; // 提示错误:Potential leak of an object
}
2. 动态内存分析
作用:
> 检测程序在运行过程中是否存在内存泄露
> 查看是内存的分配情况
> 查看内存是否有释放
名词解释:
Anonymous VM(匿名虚拟内存)是系统为程序预留的、可能会立即被重复使用的一部分可用内存
内存检测工具----Instruments
1. 使用:xcode---product----Profile----Leak;运行程序,通过使用app,若红色区域代表内存泄漏出现的地方。
2. 使用:xcode---product----Profile----Allocations;运行程序,通过使用app,可以查看做出了某个操作后(比如点击了某个按钮\显示了某个控制器), 内存是否有暴增的情况(突然变化)
3. Foundation 和 CoreFoundation框架的内存管理
MRC--ARC环境的切换方式:target -> build setting -> 搜索 automatic reference counting
> MRC 下桥接 - Foundation 和 CoreFoundation框架的数据类型转换:
1. 都是强制数据类型转换,不会移交对象内存管理所有权
// > MRC 下桥接
// 直接转换
// 1. Foundation -> CoreFoundation:
NSString *str = [[NSString alloc] initWithCString:"123" encoding:NSUTF8StringEncoding];
// 这种转换, 不会移交对象的内存管理权
CFStringRef strRef =(CFStringRef)str;
NSLog(@"%@", strRef);
[str release];
// CFRelease(strRef);
// 2. CoreFoundation -> Foundation:
CFStringRef strRef2 = CFStringCreateWithCString(CFAllocatorGetDefault(), "123", kCFStringEncodingUTF8);
// 这种转换, 不会移交对象的内存管理权
NSString *str2 = (NSString *)strRef2;
NSLog(@"%@", str2);
CFRelease(strRef2);
```
---
> ARC 下桥接 - Foundation 和 CoreFoundation框架的数据类型转换:
1. Foundation -> CoreFoundation:
1. __bridge方式 :不会移交对象内存管理所有权
2. CFBridgingRetain = __bridge_retained方式:会移交对象内存管理所有权
2. CoreFoundation -> Foundation:
1. __bridge方式 :不会移交对象内存管理所有权
2. CFBridgingRelease = __bridge_transfer方式:会移交对象内存管理所有权
```objc
// > ARC 下桥接
// 1. Foundation -> CoreFoundation:
NSString *str = [[NSString alloc] initWithCString:"123" encoding:NSUTF8StringEncoding];
// 转换方式1: __bridge CFStringRef 这种转换, 不会移交对象的内存管理权, 类似于, 直接转换
// CFStringRef strRef = (__bridge CFStringRef)(str);
// 转换方式2: CFBridgingRetain == __bridge_retained CFStringRef , 这种方式转换, 会移交对象的内存管理权
CFStringRef strRef = (__bridge_retained CFStringRef)(str);
NSLog(@"%@", strRef);
CFRelease(strRef);
// 2. CoreFoundation -> Foundation:
CFStringRef strRef2 = CFStringCreateWithCString(CFAllocatorGetDefault(), "123", kCFStringEncodingUTF8);
// 转换方式1: (__bridge NSString *) 直接转换, 不会移交对象的内存管理权
// NSString *str2 = (__bridge NSString *)(strRef2);
// 转换方式2: CFBridgingRelease == __bridge_transfer NSString * 会移交对象的内存管理权
NSString *str2 = (__bridge_transfer NSString *)(strRef2);
NSLog(@"%@", str2);
4. 内存分析工具
5. OC内存使用总结
1. 如何让程序尽量减少内存泄漏
1.非ARC
1. Foundation对象(OC对象) : 只要方法中包含了alloc\new\copy\mutableCopy\retain等关键字, 那么这些方法产生的对象,就必须在不再使用的时候调用1次release或者1次autorelease
2. CoreFoundation对象(C对象) : 只要函数中包含了create\new\copy\retain等关键字,那么这些方法产生的对象, 就必须在不再使用的时候调用1次CFRelease或者其他release函数
2. ARC
只自动管理OC对象, 不会自动管理C语言对象
* CoreFoundation对象(C对象) : 与非ARC一致
6. swift的内存管理
- 通过arc管理内存
- 关于Swift中使用CoreFoundation数据类型,使用了"类型重映射"机制, 转换成为了能够自动管理内存的对象,不需要我们手动释放
7. 图片加载的内存分配
> imageNamed:图片会在内存中有缓存, 而且不会被释放
> 基本上,除此之外的图片加载方法:图片没有缓存,可以被释放
补充:
1. 图片在沙盒中的存在形式
1.如果项目的Deployment Target <= 6.x (不支持图片压缩);
1> 所有图片直接暴露在沙盒的资源包(main Bundle), 不会压缩到Assets.car文件
2.如果项目的Deployment Target >= 7.x (支持图片压缩)
1> 放在Images.xcassets里面的所有图片会压缩到Assets.car文件, 不会直接暴露在沙盒的资源包(main Bundle)
2> 没有放在Images.xcassets里面的所有图片会直接暴露在沙盒的资源包(mainBundle),不会压缩到Assets.car内
2. 图片加载方法
放在Images.xcassets里面的所有图片 : 无法得到图片的全路径,只能通过图片名(imageNamed:方法)来加载图片
没有放在Images.xcassets里面的所有图片:可以获取全路径,可以使用所有方法加载
3.结论:
小图片\使用频率比较高的图片;放在Images.xcassets里面
大图片\使用频率比较低的图片(一次性的图片, 比如版本新特性的图片);不要放在Images.xcassets里面
4. 怎样解压.car压缩包, 获取资源:https://github.com/devcxm/iOS-Images-Extractor
8. 内存/性能优化