多次点击屏幕、网络导致内存泄漏,导致真机崩溃
Memory leaks by click screen, network many times, lead to crash in real device
当用户测试我的应用程序时,他像猴子一样快速地随机点击屏幕,进入我的每一个细节view controller
,因为每一个都进入我的细节vc
,vc
将 fetch data
来自网络。在真实设备中,我的应用 crash
。
我认为这个问题是由 memory leak
引起的,因为它没有出现在 simulator
中,我在 instrument
中测试了我的应用程序,下面的 screenshoot
:
仪器中:
情况:
我的主屏幕,单击主屏幕上的每个 item
将进入不同的详细信息 vc
。
详细一个vc
,每个详细vc
,用户测试会fetch data
或点击随机:
内存增长到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" 工具(参见 )有助于追踪这些问题。
当用户测试我的应用程序时,他像猴子一样快速地随机点击屏幕,进入我的每一个细节view controller
,因为每一个都进入我的细节vc
,vc
将 fetch data
来自网络。在真实设备中,我的应用 crash
。
我认为这个问题是由 memory leak
引起的,因为它没有出现在 simulator
中,我在 instrument
中测试了我的应用程序,下面的 screenshoot
:
仪器中:
情况:
我的主屏幕,单击主屏幕上的每个
item
将进入不同的详细信息vc
。详细一个
vc
,每个详细vc
,用户测试会fetch data
或点击随机:内存增长到
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" 工具(参见