UIImagePicker 的内存问题
Posted
技术标签:
【中文标题】UIImagePicker 的内存问题【英文标题】:Memory Troubles with UIImagePicker 【发布时间】:2011-02-24 16:19:24 【问题描述】:我正在构建一个包含几个不同部分的应用程序,所有这些部分都非常注重图像。它与我客户的网站相关联,它们是“高设计”类型的服装。
应用程序的一部分是从相机或库上传的图像,以及显示缩略图网格的表格视图。相当可靠,当我处理 UIImagePickerControl 的相机版本时,我会因为内存不足而受到打击。如果我在应用程序的该部分反弹一段时间,我偶尔会在调试器中出现“status:10 (SIGBUS)”且不可重复地崩溃。
在内存不足警告时,我的应用程序这方面的根视图控制器转到我的数据管理单例,浏览缓存数据数组,并杀死最大的部分,即与每个条目关联的图像。因此:
- (void)didReceiveMemoryWarning
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Low Memory Warning"
message:@"Cleaning out events data"
delegate:nil
cancelButtonTitle:@"All right then."
otherButtonTitles:nil];
[alert show];
[alert release];
NSInteger spaceSaved;
DataManager *data = [DataManager sharedDataManager];
for (Event *event in data.eventList)
spaceSaved += [(NSData *)UIImagePNGRepresentation(event.image) length];
event.image = nil;
spaceSaved -= [(NSData *)UIImagePNGRepresentation(event.image) length];
NSString *titleString = [NSString stringWithFormat:@"Saved %d on event images", spaceSaved];
for (WondrMark *mark in data.wondrMarks)
spaceSaved += [(NSData *)UIImagePNGRepresentation(mark.image) length];
mark.image = nil;
spaceSaved -= [(NSData *)UIImagePNGRepresentation(mark.image) length];
NSString *messageString = [NSString stringWithFormat:@"And total %d on event and mark images", spaceSaved];
NSLog(@"%@ - %@", titleString, messageString);
// Relinquish ownership any cached data, images, etc that aren't in use.
如您所见,我正在(糟糕的)尝试观察我正在释放的内存空间。我知道它并没有告诉我 UIImages 本身的实际内存占用,但它至少给了我一些数字,所以我可以看到正在发生的事情。 (对于我构建 NSLog 消息的笨拙方式感到抱歉——我打算触发另一个 UIAlertView,但意识到记录它会更有用。)
相当可靠,在应用程序的图像部分处理了一段时间后,我将拉起相机界面并快速连续三四次获得低内存 UIAlertView。这是我上次看到的 NSLog 输出:
2010-05-27 08:55:02.659 EverWondr[7974:207] Saved 109591 on event images - And total 1419756 on event and mark images
wait_fences: failed to receive reply: 10004003
2010-05-27 08:55:08.759 EverWondr[7974:207] Saved 4 on event images - And total 392695 on event and mark images
2010-05-27 08:55:14.865 EverWondr[7974:207] Saved 4 on event images - And total 873419 on event and mark images
2010-05-27 08:55:14.969 EverWondr[7974:207] Saved 4 on event images - And total 4 on event and mark images
2010-05-27 08:55:15.064 EverWondr[7974:207] Saved 4 on event images - And total 4 on event and mark images
然后很快我们就得到了 SIGBUS 出口。所以情况就是这样。现在我的具体问题:
我看到这种情况发生的时间是 UIPickerView 的相机光圈关闭时。我单击按钮拍照,它执行“单击”动画,Instruments 显示我的内存占用量从大约 10mb 到大约 25mb,并坐在那里,直到图像传送到我的 UIViewController,使用量回落到 10 或又是 11mb。如果我们在没有记忆警告的情况下通过它,我们就是黄金,但很可能我们没有。我能做些什么来让它不那么贵?
其次,我启用了 NSZombies。我是否正确理解这实际上是在阻止内存被释放?我是否将我的应用置于不公平的测试环境中?
第三,有没有办法以编程方式获取我的内存使用情况?或者至少是 UIImage 对象的用法?我已经搜索了文档,但没有看到任何相关内容。
【问题讨论】:
我认为当您收到内存警告时调用 UIImagePNGRepresentation 是个坏主意,它将分配 更多 内存。 是的,这当然不是生产代码方法。在试图弄清楚发生了什么事情时,有点像冰雹玛丽传球。 【参考方案1】:这些函数让您了解您的总内存使用量和总可用内存。我的应用中碰巧有一个 1 秒计时器,它每秒记录已使用和可用内存空间(如果更改 > 0.5mb),它可以帮助我更好地了解正在发生的事情:
#import "mach/mach.h"
vm_size_t usedMemory(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);
return (kerr == KERN_SUCCESS) ? info.resident_size : 0; // size in bytes
natural_t freeMemory(void)
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t pagesize;
vm_statistics_data_t vm_stat;
host_page_size(host_port, &pagesize);
(void) host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
return vm_stat.free_count * pagesize;
EDIT1 - 函数class_getInstanceSize 为您提供对象实例的大小,但我从未尝试过它,它可能不会取消引用 ivars 并汇总它们的使用情况。但也许它可以帮助你。
EDIT2此函数为您提供 UIImage 的大小:
size_t sizeofUIImage(UIImage* image)
return CGImageGetBytesPerRow(image.CGImage) * CGImageGetHeight(image.CGImage);
EDIT4 这是我的 1 秒计时器处理程序方法中的一些代码,它有助于在出现内存问题之前了解您的应用程序的运行情况。当然,可用内存取决于正在运行的后台任务(Safari、Mail 等)而您无法控制:
void logMemUsage(void)
// compute memory usage and log if different by >= 100k
static long prevMemUsage = 0;
long curMemUsage = usedMemory();
long memUsageDiff = curMemUsage - prevMemUsage;
if (memUsageDiff > 100000 || memUsageDiff < -100000)
prevMemUsage = curMemUsage;
NSLog(@"Memory used %7.1f (%+5.0f), free %7.1f kb",
curMemUsage/1000.0f, memUsageDiff/1000.0f, freeMemory()/1000.0f);
致谢:来自here 和here 的内存空闲/使用函数。
【讨论】:
我的 C 很差(而我的 Obj-C 只是稍微好一点)。我将它粘贴到我的视图控制器中,并且在每一行都出现了编译错误。有什么我需要包含的吗? 对不起,你需要#import "mach/mach.h" 我还添加了一个 freeMemory() 函数。见上文。 谢谢。什么是“size_t”?我可以把它当作一个 int 对待吗? 是的,size_t 通常是 unsigned long 或类似的。上面的 Edit4 显示了我如何在我的 1 秒计时器方法中记录这些信息,只是为了给你一个想法。我希望这对您的第三个问题有所帮助。以上是关于UIImagePicker 的内存问题的主要内容,如果未能解决你的问题,请参考以下文章
iPhone 中 UIImagePickerController 的内存泄漏问题