了解NSAutoreleasePool

Phi*_*ell 1 objective-c nsautoreleasepool ios

我有一个应用程序,在iPhone 4s上使用相机时会收到内存警告.我在使用它之前缩放图像.

+ (UIImage*)simpleImageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{

// Create a graphics image context
UIGraphicsBeginImageContext(newSize);

// Tell the old image to draw in this new context, with the desired
// new size
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];

// Get the new image from the context
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();

// End the context
UIGraphicsEndImageContext();


// Return the new image.
return newImage;
}
Run Code Online (Sandbox Code Playgroud)

我读到你应该从这里使用NSAutoreleasePool http://wiresareobsolete.com/2010/08/uiimagepickercontroller/

所以我修改了这样的代码:

+ (UIImage*)simpleImageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{
//http://wiresareobsolete.com/2010/08/uiimagepickercontroller/

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

// Create a graphics image context
UIGraphicsBeginImageContext(newSize);

// Tell the old image to draw in this new context, with the desired
// new size
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];

// Get the new image from the context
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();

// End the context
UIGraphicsEndImageContext();

[newImage retain];

[pool release];

// Return the new image.
return newImage;
}
Run Code Online (Sandbox Code Playgroud)

记忆警告消失了.我没有在一个单独的线程上调用它.这个NSAutoreleasePool在做什么?我只是不明白.

我可以在本地NSAutoreleasePool中保留一个对象吗?

NSAutoreleasePool发布后,我可以使用保留的对象吗?

重要的问题:NSAutoreleasePool的这种特定用法如何帮助我的应用程序的内存占用,以便它不会得到内存警告?

new*_*cct 6

首先,你应该使用@autoreleasepool块而不是NSAutoreleasePool对象; 后者已经过时了.前者更好,因为当你离开块的范围时它会自动耗尽池,而你不需要自己明确地执行它.

自动释放池只记得在其范围内已"自动释放"的内容,并在池耗尽时释放它们."自动释放"一个对象就像释放它一样,但是推迟了; 从内存管理的角度来看,它需要一个强大的引用,并将其"传输"到池中,以便池现在具有对该对象的强引用,而您没有.在预ARC中,如果一个方法(其名称不以newor 开头copy)需要返回在函数期间创建的对象,那么它几乎必须自动释放.通过将其放在池上,它可以保证对象将处于活动状态,以便被调用函数接收.在您的代码中,UIGraphicsGetImageFromCurrentImageContext()可能会返回一个自动释放的对象.

自动释放池只在池的末端排出.池中的对象在池的持续时间内保持活动(因为池有效地"拥有"它们).这意味着如果池持续很长时间并且很多东西都被自动释放,那么就会阻止许多对象被释放,这可能是坏事.

例如,假设您的函数的一次运行自动释放一个对象(即返回的对象UIGraphicsGetImageFromCurrentImageContext()).然后,如果你在一个循环中运行你的函数100,000次,那么100,000个对象会留在内存中,因为它们被放到了没有机会排空的同一个池中.但是,如果在循环的每次迭代中放入另一级别的池,它将在每次迭代结束时耗尽,从而阻止对象构建.

至于你的第二段代码,在你的simpleImageWithImage:方法中放入一个自动释放池确实可以捕获自动释放UIGraphicsGetImageFromCurrentImageContext().但是,您还有另一个问题,因为为了从simpleImageWithImage:方法本身返回图像对象,您需要自动释放它!

您编写的方法违反了内存管理规则.您的方法返回一个保留对象,调用者必须记住该对象才能释放.但是,调用者不知道基于名称.根据命名规则,即可以返回一个保留实例的唯一方法是那些名字开始alloc,retain,new,copy,和mutableCopy.您的方法不以任何这些方法开头,因此它必须返回一个未保留的实例.由于您拥有该对象(通过保留它),您必须执行平衡释放或自动释放.您无法释放它,因为它会导致对象被释放,因为没有其他强引用,因此您只能自动释放它.

但是如果你要再次自动释放它,你在这里添加一个自动释放池没有任何成就,除非在内部drawInRect:或内部UIGraphicsGetImageFromCurrentImageContext()它们自动释放很多东西.