在iPhone 6和5s上,我在iOS上使用我的应用程序遇到了内存不足的问题。我确信内存是问题,因为我收到了内存警告,也因为崩溃日志。
在应用程序中,我进行视频处理,并在10秒内处理大约400张图像,进行一个后处理步骤。每个框架的资源都在自动释放池中正确释放。崩溃是在随机重复之后发生的。
我总共在这10秒(几百MB)内分配了大量内存,但由于自定义自动释放池,内存在每个处理过的图像之后释放。
但是,当我尝试分析问题的根源时,我甚至无法检测到高内存消耗,更不用说搜索问题的根源了。我已经分析了仪器中活动监视器中使用的物理内存,我的app和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;
}
答案 0 :(得分:4)
当在循环中进行使用自动释放内存的处理时,需要在循环中放置一个自动释放池。请注意,许多Cocoa和Foundation方法都使用自动释放的内存。
问题是每个操作都保留并自动释放内存,但是直到当前自动释放池耗尽时才会释放内存,通常是在运行循环中,并且由于紧密循环而没有被调用。
示例:
for (...) {
@autoreleasepool {
perform work
}
}
您可以将自动释放池放在操作的较小部分周围。
调试减少循环次数,这样就不会崩溃,然后使用Heapshot:
使用仪器检查由于保留但未泄漏的内存导致的泄漏和内存丢失。后者是未使用的内存,仍然指向。在仪器上的分配工具中使用标记生成(快照)。
如何使用“快照”查找内存褶皱,请参阅:bbum blog
基本上,该方法是运行Instruments分配工具,获取快照,运行代码的迭代并重复另外3到4次快照。这将指示在迭代期间分配但未释放的内存。
要弄清楚披露的结果,以查看个别分配。
如果您需要查看对象使用仪器的保留,释放和自动释放的位置:
在仪器中运行,在分配中设置“记录参考计数”(对于Xcode 5及更低版本,您必须停止记录以设置选项)。导致应用程序运行,停止录制,向下钻取,您将能够看到所有保留,发布和自动释放的位置。
答案 1 :(得分:0)
问题是有一个CIImage在自动释放池之外和渲染方法之外被解除引用,我已经在问题中发布了。
作为参数传递的是targetImage参数。所以现在我在方法调用之外添加了另一个自动释放池,它修复了我所有的内存问题。
对于我来说,这仍然是一个谜,但为什么那些未发布的CIImage分配并没有体现在内存监视器和其他工具中使用的内存量上。
另外,我不明白为什么坠毁只会偶尔发生。