iPad上的drawRect导致内存问题

Posted

技术标签:

【中文标题】iPad上的drawRect导致内存问题【英文标题】:drawRect on iPad causing memory problems 【发布时间】:2011-08-27 17:31:18 【问题描述】:

我有一个 5-tab Tab Bar Controller iPad 应用程序。 选项卡之一 (EKG) 导致内存问题。我已经运行了 Instruments,我所能看到的只是 malloc 分配不断增加,大约 12 分钟后,我的所有视图控制器首先获得 didReceiveMemoryWarning 级别 1,然后是级别 2,然后是 SigAbort 0 termination

应用程序设计的工作方式是当 EKG 选项卡处于活动状态时,每 200 毫秒触发一次setNeedsDisplay,以便在屏幕上绘制(绘制)EKG 样本。当我让应用程序正常运行时,它会在大约 12 分钟后终止。

但是,如果我保留 setNeedsDisplay 并注释掉 drawRect 中的代码,它将运行 永远。我不知道我的“drawRect”中有任何内存分配,但有人在做这些mallocs 下面是我的drawRect 代码:

- (void) drawRect : (CGRect) rect 

    int i, ii, x = 0, xx, y;        

    fEcgDraw = YES;     
    CGContextRef context = UIGraphicsGetCurrentContext ();
    CGContextSetLineWidth (context, 1);             
    HH = 376;                               
    if (fEcgErase == YES)                           
    
        CGContextSetStrokeColorWithColor (context,      
                     [UIColor blackColor].CGColor);
/*==============================================================================*/
/* Erase the last screen.                                                       */
/*==============================================================================*/
        for (i = 0; i < 120; i++)                   
                
            CGContextMoveToPoint (context,          
                          ECGX[x],
                          (HH - ECGS[x]));      
            CGContextAddLineToPoint (context, ECGX[(x + 1)],    
                         (HH - ECGS[((x + 1) % 119)])); 
            x++;                            
           // end - for (i = 0; i < 120; i++)
        CGContextStrokePath (context);          
        fEcgErase = NO;             
       // end - if (fEcgErase == YES)
    else if (fECGLOOP)                  
    
        xx = 1;             
        x = 0;                  
        y = YY;                         
        ii = 0;             
        for (i =
         
//          if (xx == 1)                
            
/*==============================================================================*/
/* First erase the prior ECG A/D plot value.                                    */
/*==============================================================================*/
                CGContextSetStrokeColorWithColor (context,  
                        [UIColor blackColor].CGColor);  
                CGContextMoveToPoint (context,          
                            ECGX[x],    
                            (HH - ECGS[x]));
                CGContextAddLineToPoint (context,       
                            ECGX[(x + 1)],      
                            (HH - ECGS[((x + 1))]));
                CGContextStrokePath (context);          
/*==============================================================================*/
/* Now plot the next ECG A/D plot value.                                        */
/*==============================================================================*/
                CGContextSetStrokeColorWithColor (context,  
                        [UIColor whiteColor].CGColor);  
                CGContextMoveToPoint (context,      
                              ECGX[x],      
                              (HH - ECGY[y]));  
                CGContextAddLineToPoint (context,   
                             ECGX[(x + 1)],     
                             (HH - ECGY[((y + 1) % 119)])); 
                CGContextStrokePath (context);          
                ECGS[x] = ECGY[y];      
                x++;                
                y = ((y + 1) % 119);        
               // end - if (xx == 1)
               // end - for (i = 0; i < 120; i++)
        y = ((y + count1) % 119);               
        YY = y;                         
        count1 = 0;                 
       // end - if (fEcgErase == YES)
    fEcgDraw = NO;                              

   // end - 'drawRect'
/*===============================END OF FUNCTION================================*/

【问题讨论】:

我已经尝试注释掉“drawRect”并留在“setNeedsDisplay”中,这样​​问题就消失了。我不理解您对 iver 和 gvars 的评论,尤其是 gvars,因为根据定义它们只有一个实例。至于 ivars,我不明白怎么会有多个,因为没有类实例化可以分配更多的 ivars。 【参考方案1】:

问题已通过在每个“CGContextStrokePath”之前添加“CGContextClosePath”得到解决,应用现在将永远运行而没有任何“didReceiveMemoryWarning”。

-吉尔·古德里奇

【讨论】:

【参考方案2】:

我在drawRect: 中看不到任何泄漏。您可以使用 ObjectAllocation 的工具并查看 malloc 调用上的回溯,以查看请求它们的内容。您也可以留下您的setNeedsDisplay 并注释掉您的整个drawRect:。如果内存还在增长,那么它在其他地方。

我还会查看您正在更改的 ivars 或全局 var 可能对其他线程产生的影响。例如,是否有任何其他线程读取 fEcgDrawHH 并且可能由于这些在 drawRect: 中被弄乱而无法释放内存?

【讨论】:

我认为这个问题可以通过添加 'CGContextClosePath' 来解决,可惜不是。这是最新的,如果我在 Instruments 下运行我的应用程序,它永远不会失败,也不会报告任何泄漏等。如果努力解决问题,我尝试注释掉我的“drawRect”的各个部分。这是我发现的——如果我评论所有“drawRect”它不会失败,如果我只评论“CGContextStrokePath”它永远不会失败——所以我的结论是罪魁祸首(即失去记忆)是'CGContextStrokePath'。我不知道如何纠正这个问题。有什么建议吗? 在 Instruments 中,使用 Allocations 工具,您应该会看到整体内存使用量在增长,并且您应该注意它是哪种对象。您提到它是一个 malloc,但它的大小很重要,您可以告诉仪器跟踪分配堆栈帧,以便查看生成它们的原因。 这个问题真的很奇怪,最新的是这个问题只发生在我从 Xcode 运行应用程序时(调试或不调试)——当我独立运行它时它会永远运行(测试到 1 1 /2 小时)没有问题。

以上是关于iPad上的drawRect导致内存问题的主要内容,如果未能解决你的问题,请参考以下文章

iPad SplitViewController 内存警告导致主视图出现问题

DrawRect 内存问题

iPad Mini 上的 iOS 内存管理

是drawRect----泄漏内存

内存恶鬼drawRect

drawrect 在非常大的 uiview 和内存不足