달력

07

« 2017/07 »

  •  
  •  
  •  
  •  
  •  
  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
  •  
  •  
  •  

ARC, non-ARC 소스가 같이 있는 프로젝트에서 메모리 해제가 잘 될까?


궁금해서 데이터 오브젝트를 하나 만들어 해제하는 간단한 테스트 프로젝트를 만들어 보았다.



TestARC.zip



프로젝트에 대해서 대충 설명하면, ARC을 사용하는 프로젝트를 만들고 ARC, non-ARC 소스 두개를 만든다.


@interface SMData : NSObject

@property (nonatomic, strong) NSData *data;

@end


@implementation SMData

- (id)init {
    self = [super init];
    if (self) {
        self.data = [NSMutableData dataWithCapacity:1024*1024];
    }
    return self;
}

@end

<ARC소스는 strong을 써서 1메가를 할당하는 오브젝트>


@interface SMData_noARC : NSObject

@property (nonatomic, retain) NSData *data;

@end

@implementation SMData_noARC

@synthesize data = _data;

- (id)init {
    self = [super init];
    if (self) {
        self.data = [NSMutableData dataWithCapacity:2*1024*1024];
    }
    return self;
}

- (void)dealloc {
  [_data release];
  [super dealloc];
}

@end

<non-ARC소스는 기존 방식대로 retain을 쓰고 2메가를 할당하는 오브젝트>



그리고 컴파일 에러가 나지 않게 non-ARC소스에는 -fno-objc-arc 플래그를 지정한다.



이제 Alloc, Release 하는 버튼을 만들어 데이터 오브젝트를 생성하고 해제할 수 있도록 만든다.


- (IBAction)onAlloc:(id)sender {
    self.data = [[SMData alloc] init];
}

- (IBAction)onRelease:(id)sender {
    self.data = nil;
}

- (IBAction)onAllocNoARC:(id)sender {
    self.data_noARC = [[SMData_noARC alloc] init];
}

- (IBAction)onReleaseNoARC:(id)sender {
    self.data_noARC = nil;
}


<실행화면>



이제 메모리를 생성하고 해제하는 동작이 잘 되는지 Instrument 을 통해서 확인한다.


Xcode 메뉴의 Open Developer Tool에서 Instrument을 실행한다.




Allocations을 선택한다.



Choose Target > Attach to Process 에서 TestARC을 선택한후 Record을 누르면 Allocations 모니터링을 할 수가 있다.




버튼을 누를때마다 그래프가 오르락 내리락 하는 걸 통해 정상적으로 메모리가 할당되고 삭제되는걸 확인할 수가 있고, 통계 수치를 통해서도 알 수가 있다. (Malloc 1.25MB는 ARC로 만든 데이터, Malloc 2.50MB는 non-ARC로 만든 데이터)





이로써 ARC, non-ARC 둘다 섞인 소스도 메모리 관리가 정상적으로 된다는 것을 알게 되었네요...

의심이 많다보니 오늘은 뻘짓을 좀 해봤습니다. ㅋㅋ



TestARC.zip



저작자 표시 변경 금지
신고

iOS5의 ARC(Automatic Reference Counting)은 Objective-C 객체의 메모리 관리를 자동으로 관리하는 "Compiler" 속성이다. 이 속성을 사용하면 예전에 쓰던 retain, release, autorelease, dealloc 코드는 사용할 수 없게되며 이들이 하던 역할을 컴파일 시점에 알아서 처리해준다. ARC가 허용하지 않는 코드를 사용하면 아래와 같은 에러를 뿜어낸다.


그럼, ARC을 사용하게 되면 기존 오픈소스를 사용하는데 문제가 되지 않을까 걱정을 할 수 있는데 다음과 같이 해결하면 된다.
  • 이미 컴파일된 오픈소스 라이브러리 사용
  • ARC옵션을 끈 다른 라이브러리 프로젝트를 생성해서 사용
  • 오픈소스 파일별로 ARC옵션을 끄고 사용
ARC옵션을 끄는 방법은 프로젝트 생성할 때 옵션을 끄거나 


프로젝트 Build Settings에서 Objective-C Automatic Reference Counting을 NO로 바꾸거나


프로젝트 Build Phases에서 옵션을 끌 파일들을 선택한 후 엔터를 치고 "-fno-objc-arc" 옵션을 적용해주면 된다.


그런데, ARC을 사용하는데 있어서 제약사항이 전혀 없는건 아니다.
ARC is supported in Xcode 4.2 for Mac OS X v10.6 and v10.7 (64-bit applications) and for iOS 4 and iOS 5. Weak references are not supported in Mac OS X v10.6 and iOS 4.
Xcode 4.2 for Snow Leopard does support ARC for iOS though, and Xcode 4.2 for Lion supports both Mac OS X and iOS. This means you need a Lion system to build an ARC application that runs on Snow Leopard.

Xcode 4.2 for Snow Leopard는 지원 안되고, OSX 10.6과 iOS4에서는 Weak 참조를 사용할 수가 없다. 결국 ARC을 제대로 사용하려면 Lion 시스템을 사용하고 iOS5 이상 되어야 Weak 참조를 포함해서 제대로 된 ARC을 사용할 수 있다.


사용해보기 이전에 제약사항에 대해서 먼저 알아본 것은 실컷 공부했는데 나중에 알고보니 어떤 제약이 있어서 쓸 수 없는 상황을 미연에 막기 위해서이다.

그럼 ARC란 무엇인가? retain/release하던 걸 빼고 app_code만 작성하게 해주는 컴파일 속성이다. 사람이 짜는 코드이다 보니 retain/release 쌍이 안 맞아 다양한 버그를 만들곤 하는데 이 걱정을 안하게 해주는 고마운 놈이다.


과거엔 이렇게 했다면, 
MyObj *o = [[MyObj alloc] init];
...
[o release];

ARC에서는 [o release]; 하지 않는다. release를 안 해도 컴파일러시에 자동으로 추가된다고 알면 된다.

@interface Person : NSObject
@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSNumber *yearOfBirth;
@property (nonatomic, strong) Person *spouse;
@end
@implementation Person
@synthesize firstName, lastName, yearOfBirth, spouse;
@end
- (void)contrived {
    Person *aPerson = [[Person alloc] init];
    [aPerson setFirstName:@"William"];
    [aPerson setLastName:@"Dudney"];
    [aPerson:setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];
    NSLog(@"aPerson: %@", aPerson);
}
예전의 경험대로라면 aPerson 과 NSNumber 할당한 놈에 대해 메모리가 새는 걸 막을려는 충동을 느낄테지만 ARC에서는 위 코드가 정상이다. ARC에서는 release 짝 맞추려는 노력을 하지 않아도 된다는 것이다!

그런데, 혹자는 ARC를 사용할 경우 메모리해제가 정상적으로 되지 않는다고도 한다. aPerson = nil; 처럼 nil을 넣어줬더니 정상적으로 해제가 되더라는 사람도 있고, ... 아직 익숙하지 않아서 그렇게 느끼는 건 아닐지....

아무튼 ARC를 사용할 때 얻는 장점이 많기 때문에 앞으로 시작하는 프로젝트에 대해서는 ARC만 사용해서 쓰는 걸 추천한다. 더 자세한 내용은 아래 참고자료를 참고하고, ARC 기본설명은 여기에서 마무리한다.

* 참고자료
Transitioning to ARC Release Notes


저작자 표시 변경 금지
신고


티스토리 툴바