大量内存泄漏 - CocoaLibSpotify

Posted

技术标签:

【中文标题】大量内存泄漏 - CocoaLibSpotify【英文标题】:Massive Memory Leak - CocoaLibSpotify 【发布时间】:2013-09-02 17:32:12 【问题描述】:

我正在使用 CocoaLibSpotify 库为 Spotify 搜索结果加载专辑封面。

Instruments 报告没有泄漏,静态分析也无济于事,我已经手动查看了所有处理跟踪加载专辑封面的代码,但是,在加载了几百个结果后,该应用程序消耗超过 100mb 的内存并崩溃。

我相信 CocoaLibSpotify 将图像缓存保存在内存中,但我没有找到禁用缓存的方法。有一个“flushCaches”方法,每次我收到内存警告时都会调用它,但是它无效。

这是我用来加载专辑封面的内容,我在一个数组中保留了对所有 SPImage 对象的引用,以便在提供表格视图行时可以使用它们。

[self sendRequestToURL: @"http://ws.spotify.com/search/1/track.json" withParams: @@"q": spotifySearchBar.text usingMethod: @"GET" completionHandler: ^(id result, NSError *error) 
    //after the search completes, re-enable the search button, replace the searchResults, and
    //  request the result table to reload the data
    spotifySearchBar.userInteractionEnabled = YES;
    [searchBar endEditing: YES];
    [searchResults release];
    int resultLength = [[result objectForKey: @"tracks"] count] < 100 ? [[result objectForKey: @"tracks"] count] : 100;
    searchResults = [[[result objectForKey: @"tracks"] subarrayWithRange: NSMakeRange(0, resultLength)] retain];
    for(int i = 0; i < 100; i++) 
        [albumArtCache replaceObjectAtIndex: i withObject: [NSNull null]];
    
    for(NSDictionary *trackDict in searchResults) 
        NSString *trackURI = [trackDict objectForKey: @"href"];
        [SPTrack trackForTrackURL: [NSURL URLWithString: trackURI] inSession: session callback: ^(SPTrack *track) 
            [SPAsyncLoading waitUntilLoaded: track timeout: kSPAsyncLoadingDefaultTimeout then:^(NSArray *loadedItems, NSArray *notLoadedItems) 
                if(track == nil) return;
                [SPAsyncLoading waitUntilLoaded: track.album timeout: kSPAsyncLoadingDefaultTimeout then:^(NSArray *loadedItems, NSArray *notLoadedItems) 
                    if(track.album == nil) return;
                    [SPAsyncLoading waitUntilLoaded: track.album.largeCover timeout: kSPAsyncLoadingDefaultTimeout then:^(NSArray *loadedItems, NSArray *notLoadedItems) 
                        if(track.album.largeCover == nil) return;
                        if(![searchResults containsObject: trackDict]) 
                            NSLog(@"new search was performed, discarding loaded result");
                            return;
                         else
                            [albumArtCache replaceObjectAtIndex: [searchResults indexOfObject: trackDict] withObject: track.album.largeCover];
                            [resultTableView reloadRowsAtIndexPaths: @[[NSIndexPath indexPathForRow: [searchResults indexOfObject: trackDict] inSection: 0]] withRowAnimation: UITableViewRowAnimationAutomatic];
                        
                    ];
                ];
            ];
        ];
    
    [resultTableView reloadData];
];

这是处理加载表格视图单元格的代码。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: @"artistCell"];
    if(cell == nil) 
        cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: @"artistCell"] autorelease];
    
    cell.textLabel.text = [[searchResults objectAtIndex: indexPath.row] objectForKey: @"name"];
    cell.detailTextLabel.text = [[[[searchResults objectAtIndex: indexPath.row] objectForKey: @"artists"] objectAtIndex: 0] objectForKey: @"name"];

    if([albumArtCache objectAtIndex: indexPath.row] != [NSNull null]) 
        cell.imageView.image =  ((SPImage *)[albumArtCache objectAtIndex: indexPath.row]).image;
     else
        cell.imageView.image = nil;
    

    return cell;

我真的不知道出了什么问题。任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

首先,您应该使用 SPSearch 而不是 Web API 进行搜索。

Instruments 没有显示内存泄漏的原因是没有内存泄漏 - CocoaLibSpotify 出于性能原因在内部缓存专辑和图像。因此,加载的专辑封面也会一直存在。

现在,将数百张 1024x1024 图像加载到内存中显然会很糟糕。缓解此问题的一种简单方法是不加载最大尺寸的图像 - 1024x1024 像素的表格视图通常不需要它。

否则,您可以修改 CocoaLibSpotify 以能够卸载图像。最简单的方法是向SPImage 添加一个基本上与-startLoading 相反的方法 - 即将image 属性设置为nil,将hasStartedLoadingloaded 属性设置为@ 987654328@ 并在将 spImage 属性设置为 NULL 之前调用 sp_image_release

【讨论】:

以上是关于大量内存泄漏 - CocoaLibSpotify的主要内容,如果未能解决你的问题,请参考以下文章

Android性能优化之内存泄漏

内存优化:内存抖动和内存泄漏

前端如何处理内存泄漏

Android App卡顿慢优化之解决内存抖动及内存泄漏

创建大量线程时.Net内存泄漏

ios UIWebView中的大量内存泄漏