从Open GL ES到UIImage:内存问题

时间:2014-01-27 15:01:53

标签: ios iphone memory-management opengl-es screenshot

我正在尝试从Open GL(1.1)视图中截取屏幕截图,并使用以下代码将其转换为UIImage。

这很好用,但是每次调用这个方法都会使用内存增加(泄漏?),所以我的应用程序开始使用大约19 MB,第一次调用此方法时它变为31 MB,然后是43 MB等等......实际上,当它达到大约80 MB时就会停留在那里!!

你知道导致这种行为的原因吗?

void releaseScreenshotData(void *info, const void *data, size_t size)
{
    free((void *)data);
}

- (UIImage *)fromOpenGLToUIImage
{
    [self draw];

    NSInteger myDataLength = backingWidth * backingHeight * 4;

    // allocate array and read pixels into it.
    GLuint *buffer = (GLuint *) malloc(myDataLength);
    glReadPixels(0.0f, 0.0f, backingWidth, backingHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

    // gl renders “upside down” so swap top to bottom into new array.
    for(int y = 0; y < backingHeight / 2; y++) {
        for(int x = 0; x < backingWidth; x++) {
            //Swap top and bottom bytes
            GLuint top = buffer[y * backingWidth + x];
            GLuint bottom = buffer[(backingHeight - 1 - y) * backingWidth + x];
            buffer[(backingHeight - 1 - y) * backingWidth + x] = top;
            buffer[y * backingWidth + x] = bottom;
        }
    }

    // make data provider with data.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, myDataLength, releaseScreenshotData);

    // prep the ingredients
    const int bitsPerComponent = 8;
    const int bitsPerPixel = 4 * bitsPerComponent;
    const int bytesPerRow = 4 * backingWidth;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    // CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; // Per l'opacita'
    CGBitmapInfo bitmapInfo = (CGBitmapInfo)kCGImageAlphaPremultipliedLast; // Per la trasparenza
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;

    // make the cgimage
    CGFloat larghezza = 0.0f;
    CGFloat altezza = 0.0f;

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && ([[UIScreen mainScreen] scale] == 2.00) && ([UIScreen mainScreen].bounds.size.height == 480.0f)) {
            // iPhone Retina 3.5
            larghezza = 640.0f;
            altezza = 960.0f;
        } else if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && ([[UIScreen mainScreen] scale] == 2.00) && ([UIScreen mainScreen].bounds.size.height == 568.0f)) {
            // iPhone Retina 4
            larghezza = 640.0f;
            altezza = 1136.0f;
        } else {
            // iPhone
            larghezza = 320.0f;
            altezza = 480.0f;
        }
    } else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && ([[UIScreen mainScreen] scale] == 2.00) && ([UIScreen mainScreen].bounds.size.height == 1024.0f)) {
            // iPad Retina
            larghezza = 1536.0f;
            altezza = 2048.0f;
        } else {
            // iPad
            larghezza = 768.0f;
            altezza = 1024.0f;
        }
    }

    CGImageRef imageRef = CGImageCreate(larghezza, altezza, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
    CGColorSpaceRelease(colorSpaceRef);
    CGDataProviderRelease(provider);

    // then make the UIImage from that
    UIImage *image = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);

    return image;
}

1 个答案:

答案 0 :(得分:0)

您解释情况的方式我将假设您正在从xcode的调试窗口中读取已用内存。此“已用内存”值与“活动监视器”仪器相同。它与“分配”工具非常不同。

分配工具将为您提供应用程序使用的实际当前内存(在创建和保留的对象和基元中)。

活动监视器工具将为您提供分配给应用程序以供操作系统使用的当前内存量。无论何时创建新对象(临时或非临时),您的应用程序都会从​​操作系统请求大量内存。操作系统将确定您的应用程序是否可以从额外内存中受益,或者当前分配给您的应用程序的内容是否足够。如果你的应用程序在操作系统上多次请求内存可能会给你超过你需要的内容,这样你的应用程序可以更快地工作,而不必担心释放内存并从释放的内存中重新分配。

只需将调试器“Used Memory”视为您的沙箱即可。它会根据操作系统的应用需求(以及当前处于后台的其他应用程序)来增加和减少。如果您正在寻找泄漏的内存,该视图根本不会提供任何信息。为此目的使用“分配”工具。