【问题标题】:VM Tracker shows large Dirty SizeVM Tracker 显示较大的 Dirty Size
【发布时间】:2013-03-07 14:00:36
【问题描述】:

在我的应用程序的一部分中,我同时执行操作。它们包括初始化许多 CALayer 并将它们渲染为位图。

不幸的是,在这些操作期间(在 iphone 4 上完成每个操作大约需要 2 秒),VM Tracker 指示的脏大小飙升至 ~120MB。分配飙升至〜12MB(不累积)据我了解,脏大小是无法释放的内存。很多时候,我的应用程序和后台的所有其他应用程序都会被杀死。

Incident Identifier: 7E6CBE04-D965-470D-A532-ADBA007F3433
CrashReporter Key:   bf1c73769925cbff86345a576ae1e576728e5a11
Hardware Model:      iPhone3,1
OS Version:          iPhone OS 5.1.1 (9B206)
Kernel Version:      Darwin Kernel Version 11.0.0: Sun Apr  8 21:51:26 PDT 2012; root:xnu-

1878.11.10~1/RELEASE_ARM_S5L8930X
Date:                2013-03-18 19:44:51 +0800
Time since snapshot: 38 ms

Free pages:        1209
Active pages:      3216
Inactive pages:    1766
Throttled pages:   106500
Purgeable pages:   0
Wired pages:       16245
Largest process:   Deja Dev

Processes
         Name                 UUID                    Count resident pages
            geod <976e1080853233b1856b13cbd81fdcc3>     338
        LinkedIn <24325ddfeed33d4fb643030edcb12548>    6666 (jettisoned)
    Music~iphone <a3a7a86202c93a6ebc65b8e149324218>     935
        WhatsApp <a24567991f613aaebf6837379bbf3904>    2509
      MobileMail <eed7992f4c1d3050a7fb5d04f1534030>     945
         Console <9925a5bd367a7697038ca5a581d6ebdf>     926 (jettisoned)
        Test Dev <c9b1db19bcf63a71a048031ed3e9a3f8>   81683 (active)
     MobilePhone <8f3f3e982d9235acbff1e33881b0eb13>     867
     debugserver <2408bf4540f63c55b656243d522df7b2>      92
        networkd <80ba40030462385085b5b7e47601d48d>     158
         notifyd <f6a9aa19d33c3962aad3a77571017958>     234
      aosnotifyd <8cf4ef51f0c635dc920be1d4ad81b322>     438
        BTServer <31e82dfa7ccd364fb8fcc650f6194790>     275
CommCenterClassi <041d4491826e3c6b911943eddf6aaac9>     722
     SpringBoard <c74dc89dec1c3392b3f7ac891869644a>    5062 (active)
      aggregated <a12fa71e6997362c83e0c23d8b4eb5b7>     383
            apsd <e7a29f2034083510b5439c0fb5de7ef1>     530
         configd <ee72b01d85c33a24b3548fa40fbe519c>     465
     dataaccessd <473ff40f3bfd3f71b5e3b4335b2011ee>     871
   fairplayd.N90 <ba38f6bb2c993377a221350ad32a419b>     169
       fseventsd <914b28fa8f8a362fabcc47294380c81c>     331
            iapd <0a747292a113307abb17216274976be5>     323
         imagent <9c3a4f75d1303349a53fc6555ea25cd7>     536
       locationd <cf31b0cddd2d3791a2bfcd6033c99045>    1197
   mDNSResponder <86ccd4633a6c3c7caf44f51ce4aca96d>     201
    mediaremoted <327f00bfc10b3820b4a74b9666b0c758>     257
    mediaserverd <f03b746f09293fd39a6079c135e7ed00>    1351
       lockdownd <b06de06b9f6939d3afc607b968841ab9>     279
          powerd <133b7397f5603cf8bef209d4172d6c39>     173
         syslogd <7153b590e0353520a19b74a14654eaaa>     178
           wifid <3001cd0a61fe357d95f170247e5458f5>     319
  UserEventAgent <dc32e6824fd33bf189b266102751314f>     409
         launchd <5fec01c378a030a8bd23062689abb07f>     126

**End**

仔细观察,脏内存主要由 Image IO 和 Core Animation 页面组成。由数百到数千页组成的多个条目。 Image IO 和 Core Animation 到底是做什么的?以及如何减少脏内存?

编辑:尝试在串行队列上执行此操作,但脏内存大小没有改善

另一个问题。 Dirty Memory 和分配有多大?

更新:

- (void) render
{
    for (id thing in mylist) {
        @autorelease {
            CALayer *layer = createLayerFromThing(thing);
            UIImage *img = [self renderLayer:layer];
            [self writeToDisk:img];
        }
    }
}

在 createLayerFromThing(thing);我实际上创建了一个包含大量子层的层

更新

maxConcurrentOperationCount = 4 的第一个屏幕截图

maxConcurrentOperationCount = 1 秒

============================================== ==================================================== ==================================================== ============

而且由于它减少了并发操作的数量几乎没有产生任何影响, 我决定尝试 maxConcurrentOperationCount = 10

【问题讨论】:

  • iOS 使用 ImageIO 来解码图像。您是在处理高分辨率图像还是使用大量图像?
  • 我正在使用大量的 CALayers 并对其进行栅格化
  • 最终图像分辨率是多少?
  • 然后将它们写入磁盘。它们稍后将用于用户界面。所以它们不是很大,每个 ~35KB 260 x 260。我一次处理 30-50 个光栅化图像
  • 260 x 260 = 67,600 像素。如果每个像素都有 3 个字节的分量,则每个图像在内存中占用 202,800 个字节。 50 * 202,800 字节 = 10,140,​​000 字节。听起来问题不大。你在使用 ARC 吗?

标签: ios objective-c memory-management instruments


【解决方案1】:

如果没有任何细节,很难说出了什么问题,但这里有一些想法。

A.使用@autorelease。 CALayers 在后台生成位图,如果不及时释放,总体上会占用大量空间。如果您要创建和渲染许多层,我建议您在渲染循环中添加一个自动释放块。如果您的所有图层都嵌套并且同时需要进行渲染,这将无济于事。

- (void) render
{
    for (id thing in mylist) {
        @autorelease {
            CALayer *layer = createLayerFromThing(thing);
            [self renderLayer:layer];
        }
    }
}

B.此外,如果您使用 CGBitmapCreateContext 进行渲染,您是否调用了匹配的 CGContextRelease?这也适用于 CGColorRef。

C.如果您使用 malloc 或 calloc 分配内存,您是否在完成后释放它?确保这种情况发生的一种方法

发布渲染循环的代码以提供更多上下文。

【讨论】:

  • A.是的,我确实使用 Autorelease B & C 是的,彻底检查了内存泄漏和堆增长
  • 我正在光栅化的每一层(包括所有子层)大约 200KB 的胭脂规(因为有很多对象)。我在想它可能会占用更多的虚拟内存来处理 CALayers
  • 这似乎不是什么难以管理的事情。你有任何可以发布的代码吗?
  • 200KB 的分配就可以了。我担心它的虚拟内存。不幸的是,除了发布我的大部分项目之外,我无法提供更多信息。我想我应该尽可能避免使用核心动画
  • 在我看来,内存仍然被保留在某个地方并且被阻止被释放。这些层是否添加到另一个集合(字典、数组、映射表......)?
【解决方案2】:

我认为这里有两种可能:

  1. 您创建的项目不会自动发布。
  2. 由于您正在执行的并发操作的数量,您占用的内存就是这样。

在第一种情况下,解决方案很简单。在创建图层和图像时向它们发送autorelease 消息。

在第二种情况下,您可以使用NSOperationQueue 来限制并发操作的数量。操作队列有一个名为maxConcurrentOperationCount 的属性。我会尝试使用 4 的值,看看内存行为与您当前的行为有何变化。当然,您可能必须尝试不同的值才能获得正确的内存与性能平衡。

【讨论】:

  • 这就是我所相信的,并且最小化并发操作的数量确实会降低分配。但它太小了,与虚拟内存没有太大区别:/
【解决方案3】:

Autorelease 将等到运行循环结束时进行清理。如果你显式释放它可以从堆中取出它而不填满池。

- (void) render {
    for (id thing in mylist) {
        CALayer *layer = createLayerFromThing(thing);    // assuming this thing is retained
        [self renderLayer:layer];                        
        [layer release];                                 // this layer no longer needed  
    } }

还可以使用分析运行构建,看看是否有泄漏并修复它们。

【讨论】:

    猜你喜欢
    • 2012-01-05
    • 2012-07-26
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 2011-04-30
    • 2015-11-01
    • 1970-01-01
    • 2011-05-06
    相关资源
    最近更新 更多