加载大量图片到collection view时App崩溃报malloc: can't allocate region错误
这个错误是典型的*内存溢出(OOM)*问题,加载大量图片时未做合理内存管理,导致系统无法分配新的内存空间触发崩溃。
"malloc: can't allocate region"
*** mach_vm_map(size=3145728, flags: 100) failed (error code=3)
报错信息里的3145728字节对应3MB左右的内存申请请求,说明申请分配单张3MB左右的图片内存时已经没有可用空间。
核心原因
大量原始图片直接加载到内存后没有及时释放,超出了APP可用的内存上限:如果同时加载上百张3MB级别的图片,就会占用数百MB内存,collection view如果没有做cell复用、图片裁剪、缓存阈值限制,内存会持续上涨直到无法分配触发崩溃。
排查步骤
- 先通过Xcode的Debug Memory Graph和Memory Report工具复现操作,查看内存占用走势,确认是否持续上涨无回落,同时排查是否有循环引用导致图片对象无法释放
- 检查图片加载逻辑:是否把下载的原始分辨率图片直接赋值给UIImageView,没有做压缩、裁剪处理
- 检查collection view cell复用逻辑:是否在cell复用的时候没有清空旧的图片加载任务,导致滑出屏幕的cell对应的图片仍然在下载并加载到内存
- 检查缓存策略:是否只做了内存缓存没有做磁盘缓存,且内存缓存没有设置上限,所有加载过的图片都常驻内存
解决方案
- 图片预加工:下载完成后先根据UIImageView的显示尺寸压缩裁剪图片,再赋值给视图,不要直接用原始尺寸图片。示例裁剪逻辑:
// Objective-C 裁剪示例 - (UIImage *)scaledImageWithImage:(UIImage *)image toSize:(CGSize)targetSize { UIGraphicsBeginImageContextWithOptions(targetSize, NO, [UIScreen mainScreen].scale); [image drawInRect:CGRectMake(0, 0, targetSize.width, targetSize.height)]; UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return scaledImage; }
// Swift 裁剪示例 func scaledImage(_ image: UIImage, to size: CGSize) -> UIImage { let renderer = UIGraphicsImageRenderer(size: size) return renderer.image { context in image.draw(in: CGRect(origin: .zero, size: size)) } }
- 优化cell复用:在
collectionView:cellForItemAtIndexPath:方法中,先取消cell上旧的图片下载任务,再赋值新的图片地址,滑出屏幕的cell对应未完成的下载任务直接终止 - 优化缓存策略:设置内存缓存上限,比如最多缓存100张图片或者内存占用上限为50MB,超过上限自动清理最早使用的图片缓存,同时搭配磁盘缓存,二次加载图片优先从磁盘读取不用重新下载
- 滑动优化:快速滑动时暂停高优先级的图片下载任务,滑动停止后再加载当前可视区域的图片
内容的提问来源于stack exchange,提问作者user3120670
相关产品推荐
相关产品推荐

