我在内存管理方面遇到了一些麻烦.随着今天手机上的摄像头以百万像素迅速上升,从UIImagePickerController返回的UIImages是记忆猪.在我的iPhone 4S上,UIImages约为5MB;我很难想象它们在新的和未来的模型上会是什么样的.
我的一位朋友说,处理UIImages的最佳方法是立即将它们保存到我应用程序文档目录中的JPEG文件中,并尽快释放原始的UIImage.所以这就是我一直在努力做的事情.不幸的是,即使将UIImage保存为JPEG并且在我的代码中没有引用它,它也不会被垃圾收集.
以下是我的代码的相关部分.我正在使用ARC.
// Entry point: UIImagePickerController delegate method-(voID) imagePickerController:(UIImagePickerController *)picker dIDFinishPickingMediawithInfo:(NSDictionary *)info { // Process the image. The method returns a pathname. Nsstring* path = [self processImage:[info objectForKey:UIImagePickerControllerOriginalimage]]; // Add the image to the vIEw [self addImage:path];}-(Nsstring*) processImage:(UIImage*)image { // Get a @R_403_6852@ path NSArray* paths = NSSearchPathForDirectorIEsInDomains(NSdocumentDirectory,NSUserDomainMask,YES); Nsstring* documentsDirectory = [paths objectAtIndex:0]; Nsstring* @R_403_6852@name = [self makeImage@R_403_6852@name]; // implementation omitted Nsstring* imagePath = [documentsDirectory stringByAppendingPathComponent:@R_403_6852@name]; // Get the image data (blocking; around 1 second) NSData* imageData = UIImageJPEGRepresentation(image,0.1); // Write the data to a @R_403_6852@ [imageData writeto@R_403_6852@:imagePath atomically:YES]; // Upload the image (non-blocking) [self uploadImage:imageData with@R_403_6852@name:@R_403_6852@name]; return imagePath;}-(voID) uploadImage:(NSData*)imageData with@R_403_6852@name:(Nsstring*)@R_403_6852@name { // this sends the upload job (implementation omitted) to a thread // pool,which in this case is managed by PhoneGap [self.commandDelegate runInBackground:^{ [self doUploadImage:imageData with@R_403_6852@name:@R_403_6852@name]; }];}-(voID) addImage:(Nsstring*)path { // implementation omitted: make a UIImageVIEw (set bounds,etc). Save it // in the variable iv. iv.image = [UIImage imageWithContentsOf@R_403_6852@:path]; [iv setNeedsdisplay]; NSLog(@"displaying image named %@",path); self.imageCount++;}
注意processImage方法如何引用UIImage,但它只用于一件事:制作该图像的NSData *表示.因此,在processImage方法完成后,UIImage应该从内存中释放出来,对吧?
我该怎么做才能减少应用的内存使用量?
更新
我现在意识到分配探查器的屏幕截图有助于解释这个问题.
解决方法 您的processImage方法不是您的问题.我们可以通过将其移植到Apple’s PhotoPicker demo app来测试您的图像保存代码
方便的是,Apple的示例项目与您的非常相似,有一种方法可以在计时器上重复拍摄照片.在示例中,图像不会保存到文件系统,而是累积在内存中.它伴随着这个警告:
/ *
启动计时器每1.5秒拍摄一张照片.
注意:出于本样本的目的,我们将继续无限期拍照.
请注意,我们会快速耗尽内存.您必须确定允许从相机拍摄的照片的正确阈值数量.
避免内存限制的一种解决方案是将每张拍摄的照片保存到磁盘,而不是将所有照片保存在内存中.
在内存不足的情况下,有时我们会调用“dIDReceiveMemoryWarning”方法,在这种情况下,我们可以恢复一些内存并保持应用程序运行.
* /
将您的方法添加到Apple的代码中,我们可以解决此问题.
imagePicker委托方法如下所示:
- (voID)imagePickerController:(UIImagePickerController *)picker dIDFinishPickingMediawithInfo:(NSDictionary *)info{ UIImage *image = [info valueForKey:UIImagePickerControllerOriginalimage]; [self.capturedImages removeAllObjects]; // (1) [self.imagePaths addobject:[self processImage:image]]; //(2) [self.capturedImages addobject:image]; if ([self.cameraTimer isValID]) { return; } [self finishAndUpdate]; //(3)}
(1) – 我们的补充,用于刷新每个图像捕获事件的实时内存
(2) – 我们的补充,将图像保存到文件系统并构建文件系统路径列表.
(3) – 对于我们的测试,我们使用cameraTimer来拍摄重复图像,因此不会调用finishAndUpdate.
我已经使用了您的processImage:方法,其中包含以下行:
[self uploadImage:imageData with@R_403_6852@name:@R_403_6852@name];
评论说.
我还添加了一个小的makeImage@R_403_6852@name方法:
static int imagename = 0;-(Nsstring*)makeImage@R_403_6852@name { imagename++; return [Nsstring stringWithFormat:@"%d.jpg",imagename];}
这些是我对Apple代码的唯一补充.
这是Apple原始代码的内存占用(cameraTimer不带(1)和(2))
在拍摄了约40张图像后,内存攀升至约140MB
这是添加的内存占用(cameraTimer与(1)和(2)一起运行)
文件存储方法正在解决内存问题:内存是平坦的,每个图像捕获的峰值大约为30MB.
这些测试是在iPhone5S上运行的.未压缩的图像为3264 x 2448 px,应为24mB(24位RGB). Jpeg压缩(文件系统)大小范围在250kB(0.1质量,根据您的代码)到1-2mB(0.7质量)高达~6mB(1.0质量).
在对您的问题的评论中,您建议重新加载的图像将受益于该压缩.情况并非如此:当图像加载到内存中时,必须先将其解压缩.它的内存占用量大约等于像素x颜色x每个颜色的位深度 – 无论图像存储在磁盘上的方式如何.正如jrturton所指出的那样,这至少表明你应该避免以比你需要的显示更高的分辨率加载图像.假设您有一个832 x 640的全屏(视网膜)imageVIEw,如果您的用户无法放大,则会浪费内存加载大于该值的图像.这是一个约1.6mB的实时内存占用,对您的24mMB原始内容有很大的改进(但这是你主要问题的题外话).
由于processImage似乎不是导致内存故障的原因,因此您应该考虑其他可能性:
1 /您没有内存问题.你是如何分析应用程序的?
2 / addImage或uploadImage之一是保留内存.尝试依次评论每个,以确定哪个.
3 /问题出在其他地方(由PhoneGap管理的事情?)
至于那些内存峰值,这些是由图像到数据jpeg压缩线引起的:
NSData * imageData = UIImageJPEGRepresentation(image,0.1);
在引擎盖下,即ImageIO,使用ImagePickerController时可能无法避免.请参阅此处:Most memory efficient way to save a photo to disk on iPhone?如果您切换到AVFoundation,您可以将图像作为未转换的NSData获取,这样您就可以避免尖峰.
总结以上是内存溢出为你收集整理的ios – 使用UIImagePickerController减少内存使用量全部内容,希望文章能够帮你解决ios – 使用UIImagePickerController减少内存使用量所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)