iOS 메모리 누수

6123 단어
나는 지금까지 모두 자동 메모리 관리인 줄 알았는데 무슨 메모리 유출이 있겠어.검사해 보니 내가 엑스코드를 너무 믿는 게 아니라 내가 너무 단순하다는 걸 알았어.iOS 개발에서 발생한 메모리 유출은 주로 몇 가지가 있다. (1) 대상은 방출할 수 없다.코어파운드리 대상을 사용할 때는 MRC이기 때문에 스스로 대상을 풀어야 한다는 점에 각별히 주의해야 한다.(2) 야생 지침.이곳은 비교적 위험해서 너에게 속하지 않는 대상을 호출하는데 무슨 일이 일어났는지 아무도 모른다.(3) 빈 포인터.OC라는 점은 좋다. 빈 대상에게 메시지를 보내면 오류나 붕괴가 일어나지 않는다.   메모리 유출을 감지하기 위해 나는 보통 두 가지 도구인 Analyze, Leaks를 사용한다.본고는 주로 제가 개발 과정에서 겪은 메모리 유출 문제의 원인과 해결 방안을 소개하고 이 두 가지 검사 도구를 어떻게 사용하는지에 대해 이 글을 볼 수 있으며 앞으로 계속 업데이트될 것입니다.

Analyze 테스트 문제


Memory error


1. Null passed to a callee that requires a non-null 1st parameter 호출 방법에는 비빈 매개변수가 필요합니다.e.g:
UIImage *image = [UIImage imageWithData:data];

원인: 2진 데이터 흐름을 그림으로 변환합니다. 데이터가nil이면 이 방법을 사용하지 마십시오.하지만 붕괴되지는 않을 거예요, 직접 측정해 보세요.수정:
if(data) {
  UIImage *image = [UIImage imageWithData:data];
}

2. Merrory(Core Foundation/Objective-C)


1. Potential leak of an object stored into'cs'는 객체에서 참조 계수에 1을 더하는 함수를 호출하지만 참조 계수를 1로 줄이는 함수는 호출되지 않습니다.e.g:
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);

원인:Core Foundation은 C 언어 프레임워크로 ARC가 아니라 수동으로 메모리를 방출해야 하기 때문에 비교적 구덩이입니다.수정:
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
CGColorSpaceRelease(cs);

(3) Dead store 1.Value stored to ‘payResoult’ during its initialization is never read. 'pay Resoult' 에 저장된 값은 읽은 적이 없습니다.e.g:
 NSString *str = @"Dead store ";
str = @"Dead store never used";

원인: 당신은 메모리에 공간을 신청하고 값을 저장했지만 저장한 값을 사용한 적이 없어서 메모리를 헛되이 소모했습니다.처리:소용없으니 삭제해라.
(4) Coding Conventions(Apple) Method accepting NSError** should have a non-void value to indicatie whether or not an error occurred;e.g:
- (void)doDecodeMultiple:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints results:(NSMutableArray *)results xOffset:(int)xOffset yOffset:(int)yOffset currentDepth:(int)currentDepth error:(NSError **)error;

이유: (NSError**) error -> error의 주소(&error).error가nil일 때, &error도 의미가 없습니다. 왜냐하면 계속 오류가 있을 수 없기 때문입니다.처리:당분간 어떤 대신이 알려줄 수 있는지 모르겠어요.

Leaks 테스트 문제


하나.AFNetworking e.g
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; manager.requestSerializer = [AFJSONRequestSerializer serializer];//  
manager.responseSerializer = [AFHTTPResponseSerializer serializer];//  
manager.requestSerializer.timeoutInterval = 5.0f;

[manager POST:strURL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        responseObject = [FHTool ResultDic:responseObject];
        if (responseObject) {
            if (networkInfoBLock) {
                networkInfoBLock(NetworkReturnCodeSuccess,responseObject);
            }
            
        }else {
            if (networkInfoBLock) {
                networkInfoBLock(NetworkReturnCodeFailed,nil);
            }
        }
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        NSLog(@"strURL = %@
error = %@",strURL,error.localizedDescription); if (networkInfoBLock) { networkInfoBLock(NetworkReturnCodeFailed,@{@"error":error.localizedDescription}); } }];

원인: 데이터를 요청할 때마다 AFHTTPSessionManager 대상을 만들고 ARC 모드에서는 방출할 수 없습니다.해결: 데이터 요청 클래스를 하나의 예로 봉하여 AFHTTPSessionManager 대상만 만듭니다.NetworkManager.h
#import 
#import 

typedef  void (^NetworkInfoBLock)(NetworkReturnCode networkReturnCode ,NSDictionary *responseObject);

@interface  NetworkManager : NSObject

@property (nonatomic, strong) AFHTTPSessionManager *manager;

+ (instancetype) shareNetworkManager;
// post
- (void)postNetworkByURL: (NSString *)strURL  AndParameter: (id)parameters AndNetworkSuccessBLock:
(NetworkInfoBLock)networkInfoBLock;

@end

NetworkManager.m
#import "NetworkManager.h"

@implementation  NetworkManager

+ (instancetype) shareNetworkManager {
    
    static  NetworkManager * networkManager = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        
        networkManager = [[NetworkManager alloc] init];
        
        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        manager.requestSerializer = [AFJSONRequestSerializer serializer];//  
        manager.responseSerializer = [AFHTTPResponseSerializer serializer];//  
        manager.requestSerializer.timeoutInterval = 5.0f;
        
        networkManager.manager = manager;
    });
    
    return  networkManager;
}
- (void)postNetworkByURL: (NSString *)strURL  AndParameter: (id)parameters AndNetworkSuccessBLock:
(NetworkInfoBLock)networkInfoBLock {
    
    
    [self.manager POST:strURL parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        responseObject = [FHTool ResultDic:responseObject];
        if (responseObject) {
            if (networkInfoBLock) {
                networkInfoBLock(NetworkReturnCodeSuccess,responseObject);
            }
            
        }else {
            if (networkInfoBLock) {
                networkInfoBLock(NetworkReturnCodeFailed,nil);
            }
        }
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        NSLog(@"strURL = %@
error = %@",strURL,error.localizedDescription); if (networkInfoBLock) { networkInfoBLock(NetworkReturnCodeFailed,@{@"error":error.localizedDescription}); } }]; } @end

좋은 웹페이지 즐겨찾기