UIImage,释放解压缓存?

发布于 2024-09-29 20:27:43 字数 1630 浏览 2 评论 0原文

我有一个 UIImages 数组,其中包含应用程序启动时从网络下载的一些 .jpg 图像。我还有一个表格视图,在其单元格中显示其中一些图像。问题是,当我滚动表格时,应用程序的内存消耗总是增加,直至由于内存不足而导致应用程序崩溃。表格单元格似乎可以很好地重用,所以我的理论如下。

由于表格单元格中的 UIImageView 仅保留图像数组中的元素之一,因此当该单元格被重用并为其分配新图像时,先前使用的图像当然不会被破坏(单元格释放了它,但数组仍然保留)。但是,用于保存原始图像数据(在视图第一次显示 UIImage 时计算的)的解压缓存属于 UIImage 本身,因此它也保留下来。但我只是猜测这一切。

这真的是问题所在吗?如果是这样,我该如何解决它?我的第一个想法是在将 UIImage 分配给单元格时创建 UIImage 的副本,但看起来 UIImage 无法深度复制。有没有办法告诉 UIImage 将压缩的 jpg 数据保留在内存中,但丢弃解压缩缓存? (在最坏的情况下,我想我仍然可以下载所有图像并将它们存储在本地文件中,然后从那里加载它们并在不再显示时完全释放 UIImages,但这似乎不是一个优雅的解决方案。)

- -

我无法发布原始代码(如评论中所建议的),因为自定义表格单元格和自定义视图甚至下载图像的后台线程相当复杂,但我刚刚创建了一个小型测试应用程序,它似乎表现出相同的行为。这是当用户点击 UIButton 时调用的一个小函数:

- (IBAction)onNext:(UIButton*)sender
{
    static NSMutableArray* images = nil; 
    if (!images)
    {
        NSArray* names = [NSArray arrayWithObjects:
            @"IMG_2957.JPG", 
            @"IMG_2962.JPG", 
            @"IMG_2965.JPG", 
            @"IMG_2970.JPG", 
            @"IMG_2971.JPG", 
            @"IMG_2978.JPG", 
            nil];
        images = [NSMutableArray new];
        for (int i = 0; i < names.count; ++i)
            [images addObject:[UIImage imageNamed:[names objectAtIndex:i]]];
        int i = 42;
    }
    static int current = 0;

    imageView.image = [images objectAtIndex:current];
    ++current; 
}

是的,我知道图像数组正在泄漏,这不是重点(在原始代码中,我还想在应用程序的整个生命周期中保留图像,并且仅在退出时释放)。但。根据 Memory Monitor,第一次点击后(加载所有图像,并显示第一个图像),应用程序消耗约 5MB(加载所有 jpg,其中一个解压缩)。在所有后续点击之后,内存消耗增加了约 2MB(是的,我使用 1024x768 图像进行了测试)。所以看起来之前显示的图像的解压缩数据仍然存在。我知道如果我在图像不再可见时释放图像,这不会成为问题,这也会释放解压缩的缓冲区,但如果可能的话,我想保留所有图像,并且只释放解压缩的缓冲区数据。这可能吗?

I have an array of UIImages that contains some .jpg images downloaded from the net when the app starts. I also have a table view that shows some of these images in its cells. The problem is that when I scroll the table, the app's memory consumption always increases up to the point where the app crashes due to low memory conditions. The table cells seem to be reused fine, so my theory is the following.

Since the UIImageView in a table cell only retains one of the elements in the image array, when the cell gets reused, and a new image is assigned to it, the previously used image is of course not destructed (the cell releases it, but the array still retains). However, the decompression cache used to hold the raw image data (computed the first time the UIImage is displayed by a view) belongs to the UIImage itself, so it also remains. But I'm just guessing about all this.

Can this really be the problem? If so, how can I work around it? My first idea was to create a copy of the UIImage whenever it is assigned to a cell, but looks like UIImages can't be deep copied. Is there any way to tell a UIImage to keep the compressed jpg data in memory but throw away the decompression cache? (In the worst case I guess I can still download all the images and store them in local files, then load them from there and completely release the UIImages when not displayed anymore, but this doesn't seem to be an elegant solution.)

--

I can't post the original code (as suggested in comments) as it is fairly complicated with custom table cells and custom views and even a background thread downloading the images, but I've just created a small test app and it seems to show the same behavior. Here's a little function that is called when the user taps a UIButton:

- (IBAction)onNext:(UIButton*)sender
{
    static NSMutableArray* images = nil; 
    if (!images)
    {
        NSArray* names = [NSArray arrayWithObjects:
            @"IMG_2957.JPG", 
            @"IMG_2962.JPG", 
            @"IMG_2965.JPG", 
            @"IMG_2970.JPG", 
            @"IMG_2971.JPG", 
            @"IMG_2978.JPG", 
            nil];
        images = [NSMutableArray new];
        for (int i = 0; i < names.count; ++i)
            [images addObject:[UIImage imageNamed:[names objectAtIndex:i]]];
        int i = 42;
    }
    static int current = 0;

    imageView.image = [images objectAtIndex:current];
    ++current; 
}

Yes, I know that the images array is leaking, that's not the point (in the original code I also want to retain the images for the entire lifetime of the app, and only release on quitting). But. According to Memory Monitor, after the first tap (all images get loaded, and the first one is displayed), the app consumes ~5MB (all jpgs loaded, one of them decompressed). After all subsequent taps, the memory consumption increases by ~2MBs (yep, I tested with 1024x768 images). So it looks like decompressed data of the previously displayed images is still there. I know this wouldn't be a problem if I released the image once it isn't visible anymore, and that would also release the decompressed buffer, but if possible, I'd like to retain all the images, and only release the decompressed data. Is that possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

枯叶蝶 2024-10-06 20:27:43

如果您要重复使用单元格,请确保这些单元格实现:

-(void)prepareForReuse
{
      // releasing the image
      self.imageView = nil; // Or release depending on you memory strategy
      self.labelView = nil; // get them all
}

If you're reusing cells, make sure those cells implement:

-(void)prepareForReuse
{
      // releasing the image
      self.imageView = nil; // Or release depending on you memory strategy
      self.labelView = nil; // get them all
}
沒落の蓅哖 2024-10-06 20:27:43

我不认为 UIImage 没有那么致命的内存泄漏。我一直在开发一些应用程序,由于内存限制,这些应用程序必须大量释放 UIImage,但它仍然工作正常。我相信你的图片在某个地方泄露了。向我们展示一些代码,以便有人为您指出这一点。

I don't think UIImage has no memory leaks that fatal. I have been working on few applications which has to deallocate UIImage a lot due to memory constraint, but it's still working fine. I believe your image leaks somewhere. Show us some code so someone will point that out for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文