循环中的@autoreleasepool 块不会减少内存峰值
@autoreleasepool block in loop dose not reduce memory peak
我被告知循环中的@autoreleasepool 块可以减少内存使用的峰值,直到我进行测试。测试设备是iPhone 6s with iOS 11.4.1.
我的代码:
@implementation BigMemObj{
NSMutableArray *_mutArr;
}
-(instancetype)init{
if(self = [super init]){
_mutArr = [[NSMutableArray alloc] initWithCapacity:1024*1024*30];
for(int i = 0; i < 1024*1024*30; i++){
[_mutArr addObject:@(i)];
}
}
return self;
}
- (void)viewDidLoad {
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
@autoreleasepool {
BigMemObj *mem = [[BigMemObj alloc] init];
}
}
}
- (void)viewDidLoad {
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
BigMemObj *mem = [[BigMemObj alloc] init];
}
}
我运行都测试了34秒,在测试1中,内存占用最高为458M,而在测试2中,内存占用最高为362M。并且两个测试都是三角形。
使用@autoreleaspool 块
没有@autoreleaspool 块
autoreleasepool 实现是否更改?还是编译器做了一些优化?
谢谢!
其实一切看起来都很正常。您看到的增长是这部分:
_mutArr = [[NSMutableArray alloc] initWithCapacity:1024*1024*30];
for(int i = 0; i < 1024*1024*30; i++){
[_mutArr addObject:@(i)];
}
所以在这里你将你的数字添加到一个数组 _mutArr
并且你添加了 1024*1024*30
个数组。当此循环完成时 _mutArr
有效且已满,它会保留所有这些数字。这甚至不会通过在此循环中添加另一个自动释放池来改变,因为您的数组不会释放这些数字。
现在调用此构造函数后,您有
@autoreleasepool {
BigMemObj *mem = [[BigMemObj alloc] init];
}
所以自动释放池将在这一刻被耗尽,释放 BigMemObj
实例 mem
中的所有数字,你的内存恢复正常。
您可能希望您的应用程序在不调用 @autoreleasepool
的情况下在内存中保持增长。但是,如果您删除该调用,则根本没有任何变化。原因是您的代码 none 根本使用了自动释放池。您的代码转换为(非 ARC)的内容是:
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
@autoreleasepool {
BigMemObj *mem = [[BigMemObj alloc] init];
[mem release];
}
}
[arr release];
但只有
时才需要 autoreleasepool
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
@autoreleasepool {
BigMemObj *mem = [[[BigMemObj alloc] init] autorelease];
}
}
[arr release];
需要自动释放池的情况:
NSMutableArray *allBigValues = [[NSMutableArray alloc] init];
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"profile.png"];
for(int i = 0; i<100000; i++){
@autoreleasepool {
[allBigValues addObject:[UIImage imageWithContentsOfFile:path]];
[allBigValues removeAllObjects];
}
}
如果在此代码中删除自动释放池,它将在内存中增长,直到循环结束。这样做的原因是因为 imageWithContentsOfFile
正在使用自动释放池,并且此方法生成的所有图像只有在池被排空后才会被释放。由于主池不会在循环内释放,我们需要创建另一个。
最重要的是,此代码运行良好,但一旦您删除 @autoreleasepool
部分,它就会开始在内存中增长并可能使您的应用程序崩溃。
注意 1: 您需要将图像 profile.png
添加到您的应用程序中,此代码才能正常工作(只需将其拖到源文件中,而不是资产中)。
注意 2: 我们在涉及池的地方使用 "drain" 因为这曾经是您需要池时需要调用的方法的名称删除它的对象。过去是这样的:
for(int i = 0; i<100000; i++){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[allBigValues addObject:[UIImage imageWithContentsOfFile:path]];
[allBigValues removeAllObjects];
[pool drain];
}
我被告知循环中的@autoreleasepool 块可以减少内存使用的峰值,直到我进行测试。测试设备是iPhone 6s with iOS 11.4.1.
我的代码:
@implementation BigMemObj{
NSMutableArray *_mutArr;
}
-(instancetype)init{
if(self = [super init]){
_mutArr = [[NSMutableArray alloc] initWithCapacity:1024*1024*30];
for(int i = 0; i < 1024*1024*30; i++){
[_mutArr addObject:@(i)];
}
}
return self;
}
- (void)viewDidLoad {
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
@autoreleasepool {
BigMemObj *mem = [[BigMemObj alloc] init];
}
}
}
- (void)viewDidLoad {
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
BigMemObj *mem = [[BigMemObj alloc] init];
}
}
我运行都测试了34秒,在测试1中,内存占用最高为458M,而在测试2中,内存占用最高为362M。并且两个测试都是三角形。
使用@autoreleaspool 块
没有@autoreleaspool 块
autoreleasepool 实现是否更改?还是编译器做了一些优化?
谢谢!
其实一切看起来都很正常。您看到的增长是这部分:
_mutArr = [[NSMutableArray alloc] initWithCapacity:1024*1024*30];
for(int i = 0; i < 1024*1024*30; i++){
[_mutArr addObject:@(i)];
}
所以在这里你将你的数字添加到一个数组 _mutArr
并且你添加了 1024*1024*30
个数组。当此循环完成时 _mutArr
有效且已满,它会保留所有这些数字。这甚至不会通过在此循环中添加另一个自动释放池来改变,因为您的数组不会释放这些数字。
现在调用此构造函数后,您有
@autoreleasepool {
BigMemObj *mem = [[BigMemObj alloc] init];
}
所以自动释放池将在这一刻被耗尽,释放 BigMemObj
实例 mem
中的所有数字,你的内存恢复正常。
您可能希望您的应用程序在不调用 @autoreleasepool
的情况下在内存中保持增长。但是,如果您删除该调用,则根本没有任何变化。原因是您的代码 none 根本使用了自动释放池。您的代码转换为(非 ARC)的内容是:
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
@autoreleasepool {
BigMemObj *mem = [[BigMemObj alloc] init];
[mem release];
}
}
[arr release];
但只有
时才需要autoreleasepool
NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
@autoreleasepool {
BigMemObj *mem = [[[BigMemObj alloc] init] autorelease];
}
}
[arr release];
需要自动释放池的情况:
NSMutableArray *allBigValues = [[NSMutableArray alloc] init];
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"profile.png"];
for(int i = 0; i<100000; i++){
@autoreleasepool {
[allBigValues addObject:[UIImage imageWithContentsOfFile:path]];
[allBigValues removeAllObjects];
}
}
如果在此代码中删除自动释放池,它将在内存中增长,直到循环结束。这样做的原因是因为 imageWithContentsOfFile
正在使用自动释放池,并且此方法生成的所有图像只有在池被排空后才会被释放。由于主池不会在循环内释放,我们需要创建另一个。
最重要的是,此代码运行良好,但一旦您删除 @autoreleasepool
部分,它就会开始在内存中增长并可能使您的应用程序崩溃。
注意 1: 您需要将图像 profile.png
添加到您的应用程序中,此代码才能正常工作(只需将其拖到源文件中,而不是资产中)。
注意 2: 我们在涉及池的地方使用 "drain" 因为这曾经是您需要池时需要调用的方法的名称删除它的对象。过去是这样的:
for(int i = 0; i<100000; i++){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[allBigValues addObject:[UIImage imageWithContentsOfFile:path]];
[allBigValues removeAllObjects];
[pool drain];
}