aircraft aircraft - 8 days ago 4
iOS Question

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

As the users test my app, he random click the screen very quickly, like a monkey , to into my every detail

view controller
, because every into my detail
vc
, the
vc
will
fetch data
from the net. And in the real device my app
crash
.
I think this issue is cause by
memory leak
, because this did not appear in
simulator
, I test my app in
instrument
, the
screenshoot
in below:

In instrument:

the instrument

The situation:


  1. my main screen, click the every
    item
    on the main screen will in to a different detail
    vc
    .



my main screen


  1. detail one
    vc
    , every in detail
    vc
    , user test will
    fetch data
    or click random:



enter image description here


  1. the memory grow to
    90.5MB
    , and did not come down, if use user's test method, if take more long time, will be more than
    90.5MB
    :



the memory grow to 90.5MB

I use
instrument
is not that well, and the memory is most used by
AFNetworking
, i don't know how to do with this. Someone can give advice? Most thanks in advance.

EDIT

I make the
AFHTTPSessionManager
to be a
singleton
, but I found my net request become slowly, does this affect me?

#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

Rob Rob
Answer

You'll see this behavior if you are instantiating lots of new NSURLSession objects (i.e. which will happen if you instantiate a lot of AFHTTPSessionManager objects).

For example, I wrote a simple program that instantiated 50 separate NSURLSession objects, did a simple data task for each (designated by a "sign post" under the "points of interest", below, all taking place during the region indicated by the green bar), and then immediately releasing them.

You'll see that memory went up by almost 6mb, but after roughly 2 minutes (with absolutely no intervention on my part), it only started reclaiming that memory, returning more than half of the memory previously consumed by all of those session objects. This is a reproducible pattern that I see when issuing multiple session objects.

enter image description here

This can be solved by either calling finishTasksAndInvalidate on the NSURLSession objects, or, better, by making sure your app instantiates only one session object and then uses that same session object every time. Either one of these approaches will dramatically reduce the memory profile of the app (and reusing the same session object is simply more efficient).

In short, I would ensure your detail view controller is not instantiating a new AFHTTPSessionManager object each time. Instantiate it once in your app and reuse it.

Having said that, I wonder if you might also have some other memory problem as my 50 NSURLSession objects only consumed 6mb of memory, and it sounds like you're losing more than that. So, I'd suggest fixing the above, but if you're still seeing memory consumption going up (not necessary shown in Leaks anymore, though), perhaps you have some strong reference cycle or the like. The Xcode 8 "debug memory graph" tool (see How to debug memory leaks when Leaks instrument does not show them?) can be helpful in tracking those issues down.