多次点击屏幕、网络导致内存泄漏,导致真机崩溃

Memory leaks by click screen, network many times, lead to crash in real device

当用户测试我的应用程序时,他像猴子一样快速地随机点击屏幕,进入我的每一个细节view controller,因为每一个都进入我的细节vcvcfetch data 来自网络。在真实设备中,我的应用 crash。 我认为这个问题是由 memory leak 引起的,因为它没有出现在 simulator 中,我在 instrument 中测试了我的应用程序,下面的 screenshoot

仪器中:

情况:

  1. 我的主屏幕,单击主屏幕上的每个 item 将进入不同的详细信息 vc

  2. 详细一个vc,每个详细vc,用户测试会fetch data或点击随机:

  3. 内存增长到90.5MB,并没有降下来,如果使用用户的测试方法,如果花费更长的时间,将超过90.5MB

我用instrument不太好,而且内存用得最多的是AFNetworking,不知道怎么办。有人可以给点建议吗?提前致谢。

编辑

我把 AFHTTPSessionManager改成了singleton,但是我发现我的网络请求变慢了,这对我有影响吗?

#import "Mysevers.h"
#import "AFNetworking.h"
#import "HUD.h"


static AFHTTPSessionManager *requestManager ;

@implementation Mysevers

+ (AFHTTPSessionManager *)sharedHTTPSession{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        requestManager = [AFHTTPSessionManager manager];
        requestManager.requestSerializer.timeoutInterval = 10;
    });
    return requestManager;
}


+(void)AFPOSTWithHud:(BOOL)hud andAddressname:(NSString*)addressName parmas:(NSDictionary*)parmas RequestSuccess:(void(^)(id result))success failBlcok:(void(^)(void))failBlcok
{

    if (hud) {
        //[HUD addHUD];
    
        [SVProgressHUD show];
    }

    AFHTTPSessionManager *requestManager = [Mysevers sharedHTTPSession];

    NSString *urlStr = [NSString stringWithFormat:@"%@%@",BASE_URL,addressName];
    DLog(@"%@",urlStr);

    [requestManager POST:urlStr parameters:parmas progress:^(NSProgress * _Nonnull uploadProgress) {
    
 } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        if (hud) {
            //[HUD removeHUD];
            [SVProgressHUD dismiss];
        }
        success(responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    
        if (error != nil) {
            DLog(@"error==%@",[error localizedDescription]);
            if (hud) {
                //[HUD removeHUD];
                [SVProgressHUD dismiss];
            }
            failBlcok();
        }
    
    
        return ;
    }];


}


+(void)AFGETWithHud:(BOOL)hud andAddressname:(NSString*)addressName parmas:(NSDictionary*)parmas RequestSuccess:(void(^)(id result))success failBlcok:( void(^)(void))failBlcok
{    
    if (hud) {
        //[HUD addHUD];
        [SVProgressHUD show];
    }
    AFHTTPSessionManager *requestManager = [Mysevers sharedHTTPSession];

    NSString *urlStr = [NSString stringWithFormat:@"%@%@",BASE_URL,addressName];

    DLog(@"%@",urlStr);


    [requestManager GET:urlStr parameters:parmas progress:^(NSProgress * _Nonnull downloadProgress) {
    
} success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

        if (hud) {

            //[HUD removeHUD];
            [SVProgressHUD dismiss];
        }
        success(responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        DLog(@"error==%@",[error localizedDescription]);
    
        if (hud) {
            //[HUD removeHUD];
            [SVProgressHUD dismiss];
        }
        failBlcok();
    }];
}


@end

如果您正在实例化大量新的 NSURLSession 对象(即,如果您实例化大量 AFHTTPSessionManager 对象,则会发生这种情况),您将看到此行为。

例如,我编写了一个简单的程序,它实例化了 50 个单独的 NSURLSession 对象,为每个对象执行了一个简单的数据任务(由下面 "points of interest" 下的 "sign post" 指定,所有发生在绿色条指示的区域内),然后立即释放它们。

你会看到内存增加了近 6mb,但大约 2 分钟后(我完全没有干预),它才开始回收内存,返回了之前所有内存消耗的一半以上这些会话对象。这是我在发布多个会话对象时看到的可重现模式。

这可以通过在 NSURLSession 对象上调用 finishTasksAndInvalidate 来解决,或者更好的方法是确保您的应用仅实例化一个会话对象,然后每次都使用同一个会话对象。这些方法中的任何一种都会显着减少应用程序的内存配置文件(并且重复使用相同的会话对象会更有效)。

简而言之,我会确保您的详细信息视图控制器不会每次都实例化一个新的 AFHTTPSessionManager 对象。在您的应用中实例化一次并重复使用。

话虽如此,我想知道您是否还有其他内存问题,因为我的 50 个 NSURLSession 对象只消耗了 6mb 内存,听起来您损失的内存不止于此。所以,我建议修复上面的问题,但是如果你仍然看到内存消耗在上升(虽然不再需要在 Leaks 中显示),也许你有一些强大的引用循环或类似的东西。 Xcode 8 "debug memory graph" 工具(参见 )有助于追踪这些问题。