平铺 PDF 视图正在泄漏内存(非 ARC)

Posted

技术标签:

【中文标题】平铺 PDF 视图正在泄漏内存(非 ARC)【英文标题】:Tiled PDF view is leaking memory (non ARC) 【发布时间】:2015-05-28 11:52:30 【问题描述】:

因此,我从事一个非常大且非常古老的遗留项目,该项目大约在 5 年前使用非 ARC 目标 c 代码进行编码。我接手了以前的开发人员,现在必须维护这头野兽。

该应用程序允许用户阅读作为单独文件下载的 PDF 页面。问题是在屏幕上显示 PDF 的视图严重泄漏内存。大约 5 分钟的简单分页会消耗大约 400 兆的内存。

因此,在分析应用程序时,我发现了似乎是问题所在的代码行。之前的开发者甚至留下了评论:“TODO DANNY 100% 泄露”...谢谢 Danny...

无论如何,我已经尝试了很多事情,但我一生都无法理解为什么这是内存泄漏。我的大部分工作和经验都与 ARC 项目有关,所以我很难理解为什么这段代码会泄漏。

UIView 子视图类如下所示:

- (void)dealloc 
    self.pauseDraw = YES;
    CGPDFPageRelease(pdfPage);  
    CGPDFDocumentRelease(pdfDocumentRef);
    [super dealloc];


- (id)initWithFrame:(CGRect)frame andScale:(CGFloat)scale
    if ((self = [super initWithFrame:frame]))         
        CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];

        if ([[[UIDevice currentDevice] modelName] isEqualToString:@"iPad 3G"]) 
            tiledLayer.tileSize = CGSizeMake(1024, 1024);
            tiledLayer.levelsOfDetail = 4;
            tiledLayer.levelsOfDetailBias = 4;
         else 
            tiledLayer.levelsOfDetail = 4;
            tiledLayer.levelsOfDetailBias = 4;
            tiledLayer.tileSize = CGSizeMake(2048, 2048);
        
        myScale = scale;
    
    return self;


+ (Class)layerClass 
    return [CATiledLayer class];


- (void)setPage:(CGPDFPageRef)newPage andDocument:(CGPDFDocumentRef)docRef 
    CGPDFPageRelease(pdfPage);
    CGPDFDocumentRelease(pdfDocumentRef);
    self->pdfPage = CGPDFPageRetain(newPage);
    self->pdfDocumentRef = CGPDFDocumentRetain(docRef);


- (void) releasePDFsFromMemory 
    CGPDFPageRelease(pdfPage);
    CGPDFDocumentRelease(pdfDocumentRef);


-(void)drawRect:(CGRect)r 

-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context 

    if(!self.superview)
        return;
    

    if (pauseDraw) 
        return;
       

    @autoreleasepool 
        CGRect cropBox = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);
        int rotate = CGPDFPageGetRotationAngle(pdfPage);

        CGContextSaveGState(context);   
        CGContextTranslateCTM(context, 0, 0);
        CGContextScaleCTM(context, myScale, myScale);

        switch (rotate) 
            case 0:
                CGContextTranslateCTM(context, 0, cropBox.size.height);
                CGContextScaleCTM(context, 1, -1);
                break;
            case 90:
                CGContextScaleCTM(context, 1, -1);
                CGContextRotateCTM(context, -M_PI / 2);
                break;
            case 180:
            case -180:
                CGContextScaleCTM(context, 1, -1);
                CGContextTranslateCTM(context, cropBox.size.width, 0);
                CGContextRotateCTM(context, M_PI);
                break;
            case 270:
            case -90:
                self.frame = CGRectMake(0, 0, 768, 1004);
                CGContextTranslateCTM(context, cropBox.size.height, cropBox.size.width);
                CGContextRotateCTM(context, M_PI / 2);
                CGContextScaleCTM(context, -1, 1);
                break;
        

        CGRect clipRect = CGRectMake(0, 0, cropBox.size.width, cropBox.size.height);
        CGContextAddRect(context, clipRect);
        CGContextClip(context);

        CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
        CGContextFillRect(context, clipRect);

        CGContextTranslateCTM(context, -cropBox.origin.x, -cropBox.origin.y);

        CGContextSetInterpolationQuality(context, kCGInterpolationHigh); 
        CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);

        // TODO DANNY leak here 100% ->
        CGContextDrawPDFPage(context, pdfPage);

        CGContextRestoreGState(context);
        

任何帮助将不胜感激!

提前致谢, 哎呀

【问题讨论】:

您确认这是泄漏吗?这里有关于 ex 内存过多的噪音:***.com/questions/2975240/… 是的,如果你看上面的评论“// TODO DANNY 在这里泄漏 100% ->”我已经在调用你链接中提到的这 2 个函数 我相信实际上是 Tiled PDF 视图没有被释放。每次您滑动以更改页面时,它们似乎都会创建一个新视图 - 我在 dealloc 方法中放置了一个 NSLog,它似乎仅在您关闭视图控制器时触发,但当旧视图在分页上被覆盖时永远不会触发 呃……抱歉吵了。 没问题,就像我说的,感谢任何帮助! :) 【参考方案1】:

所以我设法解决了这个问题。

问题不在于我上面粘贴的代码(为误导而道歉),问题是在父视图的 dealloc 方法中,以前的开发人员没有从超级视图中删除 tiledPDF 视图,也没有将变量设置为 nil调用释放后。

我通过在 dealloc 方法中放置一个 NSLog 发现了这一点,并且看到父视图正在解除分配,但是 2 个平铺的 PDF 子视图根本没有解除分配。

从超级视图中删除它们并将变量设置为 nil 后,两个 dealloc 方法都被触发了,并且应用程序内存使用量不会随着您的页面而永久增加!

【讨论】:

平铺 PDF 视图正在泄漏我的应用程序的内存。你能帮我吗***.com/questions/46903182/… 你能分享我的示例项目吗?

以上是关于平铺 PDF 视图正在泄漏内存(非 ARC)的主要内容,如果未能解决你的问题,请参考以下文章

内存泄漏和僵尸有啥区别?

iPhone 应用程序内存泄漏与 NSMutableArray 中的 UIImages

ARC CCSprite 内存泄漏

实际内存不断增加 - 从视图中删除子视图 - iOS (ARC)

Swift 表格视图,在表格视图单元格中播放视频,内存泄漏

单视图 IOS 7 内存泄漏