我在 iPhone 6 和 5s 上的 iOS 应用程序都遇到了内存不足崩溃的问题。我确定内存是问题所在,因为我收到内存警告以及崩溃日志。
在应用程序中,我进行了视频处理,并在 10 秒内为一个后处理步骤处理了大约 400 张图像。每个框架的资源都在自动释放池中正确释放。崩溃发生在随机重复之后。
我在那 10 秒内分配了大量内存(总共几百 MB),但由于自定义自动释放池,内存会在每次处理图像后释放。
但是,当我尝试剖析问题的根源时,我什至无法检测到高内存消耗,更不用说搜索问题的根源了。我已经在 Instruments 的事件监视器中分析了使用的物理内存,我的应用程序和 mediaserverd 在任何给定时刻都不会消耗超过 30 MB。
当我的应用程序在峰值时仅使用 30MB 内存时,为什么会发生内存崩溃?如何正确测量和调试内存消耗?
非常感谢任何指点!
这是运行时内存报告的屏幕截图:
这是崩溃日志:
Incident Identifier: 2B5E9345-964D-4F6E-87D2-5517F0C22531
CrashReporter Key: 2033c0b344ea7cbf4f153cd862d1e7b68969b42e
Hardware Model: iPhone6,2
OS Version: iPhone OS 8.1.1 (12B435)
Kernel Version: Darwin Kernel Version 14.0.0: Mon Nov 3 22:23:57 PST 2014; root:xnu-2783.3.22~1/RELEASE_ARM64_S5L8960X
Date: 2015-01-26 12:04:35 +0100
Time since snapshot: 672 ms
Free pages: 2515
Active pages: 23951
Inactive pages: 11816
Speculative pages: 643
Throttled pages: 0
Purgeable pages: 0
Wired pages: 133367
File-backed pages: 10813
Anonymous pages: 25597
Compressions: 8823352
Decompressions: 752051
Compressor Size: 83913
Uncompressed Pages in Compressor: 155021
Page Size: 16384
Largest process: RedGlam
Processes
Name | <UUID> | CPU Time| rpages| purgeable| recent_max| lifetime_max| fds | [reason] | (state)
timed <6fa98ab7f5de312b9bfed47e04e3a43e> 0.075 240 0 +5 701 50 [vm-pageshortage] (daemon) (idle)
calaccessd <0a7ad7bbfb523bfdbae43aa6f21279f6> 0.134 462 0 +47 1279 50 [vm-pageshortage] (daemon) (idle)
MobileGestaltHel <19968f31a89230a6b66e51ad668f0921> 0.028 163 0 - 522 50 [vm-pageshortage] (daemon) (idle)
awdd <58036e1703903ee798a8803de204c300> 0.123 405 0 - 1076 50 [vm-pageshortage] (daemon) (idle)
WirelessRadioMan <c4181e6d863133e8aa0c95e77a7bb206> 0.051 293 0 - 787 50 [vm-pageshortage] (daemon) (idle)
notification_pro <b143453e80393938a7ba23a0181dc52c> 0.158 148 0 - 451 50 [vm-pageshortage] (daemon)
com.apple.dt.ins <c2263ead004b339f9fe48bbdf95286c9> 30.091 255 0 - 787 50 [vm-pageshortage] (daemon)
debugserver <f00a5e2ac8f73e7e893c711d88c344a6> 24.790 208 0 - 681 50 [vm-pageshortage] (daemon)
MobileMail <4b48abd990e93dbea47db1cbf328da9e> 6.030 1518 0 - 4299 50 (resume) (continuous)
lsd <f554bd07b90a3cfc9d9ef9f8e234833c> 1.443 333 0 - 859 50 (daemon)
tccd <f2878273872231afa1a6e0af2dcb73a6> 0.619 278 0 - 861 50 (daemon)
MYAPP <417ba797cf3e39df82d79baf41050692> 389.444 105870 0 - 13874 50 (audio) (frontmost) (resume)
ptpd <a06176d3eefe3e3c8549bb4f6d340658> 1.913 817 0 - 2043 50 (daemon)
BTServer <2d0fc0974c073a0aafc9954110080950> 16.246 572 0 - 1859 50 (daemon)
wifid <43e56e539a6a3114bf4cd7646c8dd90e> 149.958 561 0 - 1564 50 (daemon)
discoveryd <68f73878299336d7872b0ae9ce3f7f08> 179.311 585 0 - 1220 100 (daemon)
locationd <5b826e2c09c23eaaa2acc2472269cb30> 4461.461 2209 0 - 5025 50 (daemon)
lockdownd <3a0b3375ad6e391da37a1f79f46843b0> 39.278 364 0 - 1345 50 (daemon)
syslogd <05f6b5e5512938a892bac5af23ab1c08> 127.902 240 0 - 818 50 (daemon)
powerd <2b4ae8758a5b3b709a97c452ec08923b> 56.978 310 0 - 579 50 (daemon)
imagent <d5e037ad2173362d8a6077788b2d7074> 13.323 529 0 - 1354 50 (daemon)
identityservices <9d4b00e3c6003685ac8697c59f4e4d38> 16.729 687 0 - 1794 50 (daemon)
vmd <c3b3270d187f3dcaa843ba73f01ff8cb> 0.482 595 0 - 2598 50 (daemon)
cfprefsd <4325eab208063b998046460a4c2ee484> 32.394 449 0 - 742 50 (daemon)
iaptransportd <4bf77076d69630e389ba64229c526723> 20.807 364 0 - 971 50 (daemon)
apsd <bb925404cb1137b09b85671a8d2c7656> 62.713 738 0 - 1892 50 (daemon)
networkd <fa2acedf0b0035269d66a72e28c3a95a> 307.451 716 0 - 1585 50 (daemon)
sharingd <1ed17c64831f32ea9cbb47e48c4d222c> 29.442 944 0 - 2298 50 (daemon)
dataaccessd <33bcaea3bc473f128685f4df14a115eb> 13.535 729 0 - 2230 50 (daemon)
SCHelper <779250b8a48638958a5922f6ae1066fa> 10.160 134 0 - 324 50 (daemon)
searchd <e5c5e5675c0935eaab5feb15ebc0b934> 5.392 888 0 - 2986 50 (daemon)
mediaserverd <a0354e528bc431958df0d50830bead36> 1080.882 91747 0 - 21944 200 (daemon)
syslog_relay <087c67d0371b324fb6df48442016ec90> 6.746 114 0 - 237 50 (daemon)
SpringBoard <96f929dd23123d8bbc9ba2a0bb48bde1> 1108.457 8031 0 - 17537 50
backboardd <e263837653b434f1880f9d37b3926998> 7219.545 7865 0 - 4676 50 (daemon)
UserEventAgent <f5a211b9c88e3fa481f2bd1ee1f5a921> 1084.316 1000 0 - 2811 100 (daemon)
fseventsd <16c9b62bb28c388ca10d54dbff18c4f8> 20.426 496 0 - 843 50 (daemon)
configd <ed40fcde35ae337ab3b70073199564b1> 117.075 537 0 - 1463 50 (daemon)
fairplayd.H2 <cae337642f6d396b82ac54e72bc0e0a4> 6.550 151 0 - 1433 50 (daemon)
wirelessproxd <ab1fa7e43a7c3f9393533404c2cc80b8> 1.814 264 0 - 986 50 (daemon)
assertiond <10ec04add18f3ecd8a8efbb1cc4e2bd6> 18.292 325 0 - 1045 50 (daemon)
aggregated <281958649a3130aab6ecb1aa47f0a6c1> 2273.629 1367 0 - 2822 50 (daemon)
distnoted <cb5e76091dc53ceeaf65290f8e197a89> 4.937 207 0 - 335 50 (daemon)
discoveryd_helpe <492c39ae2d643adca0ed971675c77406> 0.120 156 0 - 752 50 (daemon)
filecoordination <5ec159db1afe3317878b8ab794e2d7d1> 1.259 308 0 - 941 50 (daemon)
DTMobileIS <2fdc94aa5069338e815fbe3a13e3d95c> 551.592 2538 0 - 36844 50 (daemon)
gputoolsd <97e54c888a9a3978a85fd965a71e7669> 9.503 1031 0 - 2910 50 (daemon)
CommCenter <33412ab229c738c8860c70803fed173b> 787.039 1465 0 - 4737 50 (daemon)
notifyd <5fa8fd5e44c83f64be1475b882b16c82> 142.939 384 0 - 441 50 (daemon)
ReportCrash <e946799f25f833fd9b37a6a1c7b1993c> 0.039 166 0 - 551 50 (daemon)
**End**
这是我正在使用的一种效果的代码(renderAnimation2DOverFace 不分配任何内存):
- (CIImage *) render:(CIImage*)targetImage imageContext:(CIContext*) imageContext
facialFeatures:(NSArray*)facialFeatures currentFrameInd:(int)frameInd
{
if ( !facialFeatures ) return targetImage;
@autoreleasepool {
UIImage *editingImage = [[UIImage alloc] initWithCIImage:targetImage];
UIGraphicsBeginImageContextWithOptions(editingImage.size, NO, 1.0);
[editingImage drawInRect:CGRectMake( 0, 0, editingImage.size.width, editingImage.size.height)];
for ( ArtechFacialFeature *facialFeature in facialFeatures ) {
[self renderAnimation2DOverFace:facialFeature.bounds
currentFrameInd:frameInd];
}
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
targetImage = [targetImage initWithCGImage:resultImage.CGImage options:nil];
editingImage = nil;
resultImage = nil;
}
return targetImage;
}
这是另一个视频效果例程:
- (CIImage *) render:(CIImage*)targetImage imageContext:(CIContext*) imageContext
facialFeatures:(NSArray*)facialFeatures currentFrameInd:(int)frameInd
{
if ( !facialFeatures ) return targetImage;
@autoreleasepool {
CGImageRef inputImage = [imageContext createCGImage:targetImage fromRect:[targetImage extent]];
GPUImagePicture *sourcePicture = [[GPUImagePicture alloc] initWithCGImage:inputImage];
GPUImageOutput *currentOutput = [self createFilterChain:sourcePicture facialFeatures:facialFeatures
imageExtent:targetImage.extent];
[currentOutput useNextFrameForImageCapture];
[sourcePicture processImage];
UIImage *currentFilteredVideoFrame = [currentOutput imageFromCurrentFramebuffer];
targetImage = [targetImage initWithCGImage:currentFilteredVideoFrame.CGImage];
currentFilteredVideoFrame = nil;
[sourcePicture removeAllTargets];
sourcePicture = nil;
[currentOutput removeOutputFramebuffer];
currentOutput = nil;
CFRelease( inputImage );
[[GPUImageContext sharedFramebufferCache] purgeAllUnassignedFramebuffers];
}
return targetImage;
}
最佳答案
在循环中执行使用自动释放内存的处理时,您需要在循环内放置一个自动释放池。请注意,许多 Cocoa 和 Foundation 方法使用自动释放的内存。
问题是每个操作都在保留和自动释放内存,但直到当前自动释放池耗尽后内存才真正释放,通常在运行循环中并且由于紧密循环而未被调用。
例子:
for (...) {
@autoreleasepool {
perform work
}
}
您可以在操作的较小部分周围放置一个自动释放池。
要进行调试,请减少循环次数以免崩溃,然后使用 Heapshot:
使用仪器检查由于保留但未泄漏的内存而导致的泄漏和内存丢失。后者是仍指向的未使用内存。在 Instruments 的分配工具中使用标记生成(Heapshot)。
有关如何使用 Heapshot 查找内存泄漏的信息,请参阅:bbum blog
基本上,该方法是运行 Instruments 分配工具,进行一次堆快照,运行一次代码迭代,然后再次进行一次堆快照,重复 3 或 4 次。这将指示在迭代期间分配和未释放的内存。
要弄清楚结果,请查看个人分配。
如果您需要查看某个对象的保留、释放和自动释放发生在何处,请使用工具:
在 instruments 中运行,在 Allocations 中设置“Record reference counts”(对于 Xcode 5 及更低版本,您必须停止记录才能设置该选项)。让应用程序运行、停止记录、向下钻取,您将能够看到所有保留、释放和自动释放发生的位置。
关于ios - iOS 内存不足崩溃,但内存消耗为 20MB,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28149261/