新的iPad:低内存警告不出现?

我一直在开发一个graphics密集型的iPad应用程序。 我已经能够在iPad 2上挤出相当多的性能了,但是新iPad的@ 2xgraphics在内存部门打了很多拳头。 在乐器中使用活动监视器我可以看到我的应用程序的大小在300MB-400MB范围内,但是我没有收到任何低内存通知。 我正在使用一个UINavigationController来pipe理我的视图,所以进入堆栈会对内存产生累积效应,最后终止。 我没有遇到这个问题在iPad 2上,我收到低预期的内存通知。 我的应用程序已被编码,以尽可能清理,并在该设备上performance非常好。

我已经阅读了一些类似的问题问:

iOS应用程序因内存不足而死亡,但未收到内存警告
iPhone应用程序使用150 MB的内存,仍然没有低内存警告!

没有任何build议似乎有帮助。

我已经插入代码来强制发送一个低内存通知:

 [[UIApplication sharedApplication] _performMemoryWarning]; 

这会导致非活动视图按预期的方式卸载,并将内存消耗恢复到正常状态。 这使用一个私人的API,是黑客,所以出于实际的原因是不是一个解决scheme。 如何让我的设备正确响应低内存条件,让我的应用程序知道它需要清理?

我联系了Apple支持来解决我的内存问题,并询问iPad 3上的低内存警告:

由于内存警告是在主线程上传递的,所以如果应用程序阻塞主线程,您的应用程序将不会收到内存警告。

即使您的应用程序未阻止主线程,内存使用情况也有可能迅速增长,以致在应用程序被释放以释放内存之前不会传递内存警告。

当内核在各种内存压力之间转换时触发内存警告。 因此,应用程序接收到内存警告是很常见的,然后在内存耗尽的一段时间后会被杀死。 最初的内存警告释放了足够的内存来保持应用程序的活着,但是内核不足以转换到较低的内存压力水平。

因为这一切,内存警告应该被视为一个有用的数据的硬件状态和一个很好的指导你的应用程序应该在给定的设备上使用多less内存,但不应该依靠作为一种工具,以防止您的应用程序从被杀害。

也许这有助于…

iOS 5.1.1中解决了这个问题。 对于5.1用户,我已经实现了自己的内存看门狗,并发出类似于发出实际内存警告时使用的通知。

我首先在UIApplication上创build了一个类别。 这张贴通知UIImage侦听(或任何其支持caching是)卸载caching的图像。

。H

 @interface UIApplication (ForceLowMemory) + (void) forceUnload; @end 

.M

 #import "UIApplication+ForceLowMemory.h" @implementation UIApplication (ForceLowMemory) + (void)forceUnload { [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidReceiveMemoryWarningNotification object:[UIApplication sharedApplication]]; } @end 

接下来,我创build了一个内存pipe理器看门狗,如下所示:

。H

 @interface ELMemoryManager : NSObject - (void)startObserving; - (void)stopObserving; + (ELMemoryManager*) sharedInstance; @end 

.M

 #import "ELMemoryManager.h" #import "UIApplication+ForceLowMemory.h" #import <mach/mach.h> @interface ELMemoryManager() @property (nonatomic, retain) NSTimer *timer; uint report_memory(void); @end #define MAX_MEM_SIZE 475000000 @implementation ELMemoryManager @synthesize timer = timer_; static ELMemoryManager* manager; #pragma mark - Singleton + (void) initialize { if (manager == nil) { manager = [[ELMemoryManager alloc] init]; } } + (ELMemoryManager*) sharedInstance { return manager; } #pragma mark - Instance Methods uint report_memory(void) { struct task_basic_info info; mach_msg_type_number_t size = sizeof(info); kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size); if( kerr == KERN_SUCCESS ) { return info.resident_size; } else { return 0; } } - (void)startObserving { if (!self.timer) { NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:@selector(checkMemory:) userInfo:nil repeats:YES]; self.timer = timer; } [self.timer fire]; } - (void)stopObserving { [self.timer invalidate]; self.timer = nil; } - (void)checkMemory:(id)sender { uint size = report_memory(); if (size > MAX_MEM_SIZE) { NSLog(@"we've busted the upper limit!!!"); [UIApplication forceUnload]; } } #pragma mark - Memory Management - (void)dealloc { [self.timer invalidate]; [timer_ release]; [super dealloc]; } @end 

以下是我的经验。 我很高兴被纠正…

你是如何加载你的图像?

如果您正在使用:

 [UIImage imageNamed:(NSString *)] 

那么你需要确保有一个很好的理由。 如果您正在大量使用需要caching的图像,那么这是一个不错的select。 否则,我会build议你使用

 [UIIMage imageWithContentsOfFile:(NSString *)] 

iOS似乎有一些问题释放通过imageNamed加载的图像,即使不再有任何引用。 由于你的应用程序将不再有任何引用的图像,你可能不会得到内存警告。 但这并不意味着内存已经被释放了。 iOS往往会把这些图像保存在内存中的时间远远超过你想要的。 当它通常会给出一个内存警告,它只会终止该应用程序。

我也强烈build议打开自动参考计数(ARC)。

 Edit -> Refactor -> Convert to Objective-C ARC... 

我有相似的问题一段时间了。 对我的应用程序进行上述更改停止崩溃,并停止了通过imageNamed一遍又一遍重新加载相同的图像时造成的内存泄漏。

希望有所帮助。

这听起来像问题是你的图像不被释放。 根据UIImage文档 (和我的经验), imageNamed:caching它加载的图像。 因此,您应该将其用于几乎不断使用的小图标或图像,但将其用于大型图像或不经常使用的图像通常是个不错的主意。 正如user499177所说,你应该使用imageWithContentsOfFile:你可以使用[NSBundle mainBundle]方法派生path),而不是:

此方法在系统caching中查找具有指定名称的图像对象,并返回该对象(如果存在)。 如果匹配的图像对象不在caching中,则此方法从指定的文件加载图像数据,将其caching,然后返回结果对象。

我一直在努力消耗大量的内存,我的build议是:

  1. 使用alloc – init和release ,避免使用autorelease对象。
  2. 检查内存泄漏
  3. 如果您需要使用autorelease对象,请在创build对象之前使用NSAutoreleasePool ,并在完成对象的工作后耗尽该池。
  4. 如果你使用的是OpenGL,记得要删除所有创build的对象,特别是纹理
  5. 也许你应该尝试切换到ARC

兆Dittos。 这非常令人放心。 我也在做一个图像密集型的应用程序( UIImageView中的animation大量的UIImage对象),并在我的应用程序委托中有通常的内存警告代码,但它永远不会被触发。 尽pipe如此,仪器显示的问题,因为我加载图像,提请他们,并承诺他们的影像。 我正在使用ARC,摆脱CGImageRef的泄漏,但在一天结束的时候,如果您在ImageView中加载足够的图像,足够快,您将在日志,应用程序中没有任何警告的情况下崩溃委托方法callback,或仪器。 该应用程序只是从地板下面拉出来的地毯,而不是一个“你的离开”。

还没有机会在iPad2上试用这个,但不pipe怎样,都需要有一些指示,至less是一个简约的控制台消息或其他东西。 大部分的加载发生在我自己的GCD队列中,而不是主线程,尽pipe通过定义更新屏幕控制必须在主线程上完成。 所以我supupose如果这是阻止运行即将被拉,那么我想你可以只是得到一个匿名失败。 当然,这将有助于获得某种types的控制台消息。