본문 바로가기
조회 수 5648 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

+ - Up Down Comment Print Files
?

단축키

Prev이전 문서

Next다음 문서

+ - Up Down Comment Print Files
Chapter 4 Memory Management

01.png

위와 같이 두 Person 객체들이 NSColor 클래스의 blue객체를 참조하는 포인터(favoriteColor)를 가지고 있다가 참조값을 다른 NSColor 객체로 변경할 경우 blue 객체를 deallocate해야 한다. 또한 다른 NSColor 클래스의 객체들은 Person 객체들이 참조하고 있는 한 메모리에 있어야 한다. 

이를 이행하기 위한 아래와 같은 솔루션이 있다.

1. 수동 참조 카운팅: 모든 객체는 retain 카운터가 있다. 이 카운터는 다른 객체들이 해당 객체를 참조하는 개수이다. 위에서 최초 blue 객체를 참조하는 2개의 Person객체가 있어으므로 retain counter는 2였다. 이 retain counter가 0이 되면 deallocate 된다. (retain/release를 수동으로 해야한다)

2. 가비지 콜렉션: MAC OS 10.5 이후에 도입되었다. 전체 객체를 관리하며 scope 내에 해당 객체를 참조하는 변수가 없으면 deallocate 된다. (CPU 소모 그리고 malloc()을 사용 수동으로 할당된 객체들은 관리못함)

Important: Beginning in OS X v10.8, garbage collection is deprecated. Use ARC (Automatic Reference Counting) instead. To learn more about ARC, see Transitioning to ARC Release Notes.

3. 자동 참조 카운팅 (ARC): MAC OS 10.7 그리고 iOS 10.5 이후에 도입되었다. ARC로 알려져있으며 original retain-counter 메카니즘에 의존한다. 컴파일러가 retain counter의 bookkeeping을 관리한다. (위 두마리 토끼를 모두 잡음. Xcode에서 기본으로 enable되어 있음)


** Living with Manual Reference Counting

- 객체가 alloc 메소드에 의해 생성되면, retain 카운터는 1이된다. retain 카운터가 0이되면 객체는 deallocate된다.
- retain 메시지와 release 메시지를 보내 retain 카운터를 증가 또는 감소 시킬 수 있다.

예)
02.png

<규칙>
-alloc : 해당 객체에 메모리를 할당하고 레퍼런스 카운트를 1 올립니다.
-retain : 해당 객체의 레퍼런스 카운트를 1 올립니다.
-copy : 해당 객체의 복사본을 만듭니다. 그리고 복사본의 레퍼런스 카운트를 1 올립니다.
-release : 해당 객체의 레퍼런스 카운트를 1 낮춥니다.
-autorelease : 정해지지 않은 시점에 해당 객체의 레퍼런스 카운트가 -1 낮아집니다.

<한글 참조 사이트>

[문씨의 강좌] 메모리 관리
http://lab.smoon.kr/69
http://lab.smoon.kr/70
http://lab.smoon.kr/71
http://cafe.naver.com/mcbugi.cafe?iframe_url=/ArticleRead.nhn%3Fclubid=16914752%26page=1%26menuid=231%26boardtype=%26articleid=71504%26referrerAllArticles=false
http://cafe.naver.com/mcbugi.cafe?iframe_url=/ArticleRead.nhn%3Fclubid=16914752%26page=1%26menuid=231%26boardtype=%26articleid=71571%26referrerAllArticles=false
http://cafe.naver.com/mcbugi.cafe?iframe_url=/ArticleRead.nhn%3Fclubid=16914752%26page=1%26menuid=231%26boardtype=%26articleid=71591%26referrerAllArticles=false

아이폰 개발 - 한방에 끝내는 메모리 관리
http://blog.naver.com/PostView.nhn?blogId=neobundy&logNo=130077461314

[iphone] memory, retain, reference count, 메모리, 메모리관리
http://blog.naver.com/hana_815?Redirect=Log&logNo=60119561602

Objective-C 메모리 관리
http://blog.naver.com/PostView.nhn?blogId=gboarder&logNo=90096087956&redirect=Dlog&widgetTypeCall=true


** Accessor Methods

인스턴스 객체에 값을 대입하거나 호출하는 메소드는 보통 아래와 같다.

- (int)foo
{
	return foo; 
}

- (void)setFoo:(int)x
{
	foo = x; 
}



여기서 foo가 객체의 포인터라면 setter 메소드에서 인수로 새로운 객체가 와서 기존의 객체를 참조하고 있던 포인터의 값을 새로운 객체의 참조로 바꾸게된다. 이때 새로운 객체의 retain 카운터를 올려주고 기존 객체에는 retain 카운트를 내려주는 release를 해야 한다.

- (void)setFoo:(NSDate *)x
{
	[x retain]; // retain 먼저한 후 release
	[foo release];
	foo = x; 
}



만약 기존 참조 포인터 foo와 새로운 포인터 x가 같은 객체를 가리키고 있다면 위와 같이 retain/release가 필요없다. 이를 위해 아래와 같이 조건식을 추가한다.

- (void)setFoo:(NSDate *)x
{
	if (foo != x) { // 참조값이 동일한지 체크
		[foo release]; // 두 포인터가 틀린 객체를 참조한다면 기존 객체에 release 메시지 보냄
		foo = [x retain]; // x에 retain을 보내 retain counter를 올린 후 foo에 대입
	}
}



기존값을 autorelease하면 코드를 아래와 같이 작성할 수 있다.

- (void)setFoo:(NSDate *)x
{
	[foo autorelease];
	foo = [x retain]; 
}



이제 LotteryEntry.m 에서 date setter 코드를 아래와 같이 변경한다.

- (void)setEntryDate:(NSDate *)date {
    [date retain];
    [entryDate release];
	entryDate = date;
}




** Living with ARC

ARC는 컴파일러 기능으로 포인터들이 컴파일러에 의해 검사되어 위의 retaining, releasing, autoreleasing 등이 자동으로 추가되어 객체들이 필요한 만큼 사용되다 더이상 필요가 없어지면 dealloc 되도록 컴파일된다. 이 경우 retain counter 보다 객체 관계에만 집중하면 된다. 여기서 관계는 참조에 의해 정의되며 strong과 weak 타입이 있다.

- ARC 코드는 수동참조카운트 코드의 자동화이다
- ARC 사용시 코드에 retain, release, autorelease, dealloc을 호출하면 에러가 발생된다. 또한 retain, release, autorelease를 오버라이드 할 수 없다.

From: Objective-C에서 ARC에 대한 이해

<레퍼런스 카운트되는 메모리(기존방식)>
기존방식으로 아래와 같이 객체를 생성할 때 alloc/init ( 혹은 비슷한 명령어)를 사용하고, retainCount가 1로 리턴한다.
NSObject *obj = [[NSObject alloc] init];
// do some stuff
[obj release];



또한 아래와 같이 autorelease를 사용해 객체를 autorelease pool에 넣을 수 있다. 객체는 더 이상 필요가 없기 전까지 잘 있을 것이다.
-(NSObject*) someMethod {
  NSObject *obj = [[[NSObject alloc] init] autorelease];
  return obj; // will be deallocated by autorelease pool later
}



<Automatic Reference Counting>
이것은 Garbage Collection과는 다르다. Reference counted memory가 사라지는 것은 아니고 그것이 자동화 되는 것이기 때문이다. ARC를 사용하면 당신의 코드는 이렇게 짜면 된다.

NSObject *obj = [[NSObject alloc] init];
// do some stuff



ARC 전처리기는 자동으로 이렇게 바꿀 것이다

NSObject *obj = [[NSObject alloc] init];
// do some stuff
[obj release]; // **Added by ARC**



03.gif

<ARC 사용하기>
- 새로운 프로젝트: 아래와 같이 프로젝트 생성시 ARC 옵션에 체크한다.
04.png

- 기존 프로젝트: Build Setting에 있는  Objective-C Automatic Reference Counting이라는 옵션을 YES로 바꾸기만 하면 된다. 그러면 뒤에서는 -fobjc-arc 라는 컴파일러 flag를 켜는 것이다.
05.png

<ARC 때문에 강제되는 새 룰>
1. Alloc/Init

오브젝트 생성으로 끝난다. retain/release/autorelease 는 쓰면 안된다. 간접적으로 selector에서 간접적으로 호출 하는 것도 할 수 없다. @selector(retain) 과 @selector(release) 사용이 금지된다.

2. Dealloc Methods

ARC는 이것을 위해 존재하는 것이다. dealloc을 강제로 부르면 안된다. 하지만 custom한 dealloc 메소드는 만들 수 있고 필요하면 인스턴스를 해제할 수 있지만 [super dealloc]은 호출하지 말라. 이것은 컴파일러가 해줄 것이기 때문이다.

3. Properties의 선언

ARC 이전에는 컴파일러에게 public properties는 assign/retain/copy 파라메터로 메모리 관리를 해왔다. 이 파라메터들은 더 이상 ARC에서는 사용되지 않는다. 대신에 이 properties가 얼마나 많이 사용되는지 알려주기 위한 weak과 strong 파라메터가 생겼다.

4. C 구조의 Object 포인터

이것 역시 하면 안된다. 이 문서는 struct대신에 class로 저장하기를 권장한다. ARC에게 모르는 것이라고 하는 것 보다 말이 된다. 이것 때문에 골치 아플 수도 있다. 하지만 ARC 설정을 file 마다 따로 할 수 있다. "ARC를 사용하지 않는 코드 포함하기" 편을 봐라

5. id 와 void*의 형변환

id 와 void*의 형변환은 Core Foundation의 C 라이브러리와 Foundation Kit의 Objective-C 라이브러리 사이에서 자주 쓰인다. 이것은 Toll Free Bridging으로 알려져 있다.

ARC에서는 CF 객체가 메모리 관리를 위해 제어권을 갖는지 필요없는지 컴파일러에게 힌트/수식어를 줘야된다. 이 수식어(qualifier)는 __bridge, __bridge_retain 그리고 __bridge_tranfer를 포함한다. 그리고 CFRetain, CFRelease를 여전히 호출해야 된다.

이것은 심화과정 주제이며 CF objects가 뭔지 모르면 걱정안해도 된다.

6. NSAutoReleasePool을 대체할 @autoreleasepool

ARC 컴파일 코드는 NSAutoReleasePool 객체를 사용하면 안된다. 대신 @autoreleasepool{} block을 사용해라. ARC를 사용하는 프로젝트의 main.m은 좋은 예제이다.

int main(int argc, char *argv[])
{
  @autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([ExampleAppDelegate class]));
  }
}



7. 기타등등

Zone 기반 메모리 관리는 이제 그만(분명히 런타임도 물론 아니다)
NSAllocateBoject나 NSDeallocateObject도 쓸 수 없다.


<ARC 수식어(Qualifiers) - Declared Properties>

프로그래머들은 변수나 상수를 만들 때 전역으로 할 것인지 지역으로 정의할 것인지 결정을 내려왔다. 마찬가지로 우리의 properties가 다른 객체와 어떤 관계인지 결정을 내려야 한다. 우리는 strong/weak 수식어를 통해 컴파일러에게 관계를 알려줘야 한다.

Strong References

strong reference는 객체가 deallocated되면 함께 멈추는 객체에 쓴다. 다른말로 소유 관계다. 이전에 이렇게 사용하던 것들을

// Non-ARC Compliant Declaration
@property(retain) NSObject *obj;

ARC에서는 아래와 같이 클래스 인스턴스의 레퍼런스 객체 소유관계를 확실히 한다.(예를들어 소유자가 해제되기 전까지 해제되지 않는다)

// ARC Compliant Declaration
@property(strong) NSObject *obj;

Weak References

weak reference 는 객체가 해제 되더라도 멈추지 않는 객체에 쓴다.  다른 말로 소유 관계가 아닌 것이다. 예전에 이렇게 쓰던 것들을

// Non-ARC Compliant Declaration
@property(assign) NSObject *parentObj;

ARC에서는 아래와 같이 객체를 소유하지는 않지만 참조한다고 확실히 한다.(예를 들어 자식이 부모를 소유하지 않을 때 weak reference를 쓴다)

// ARC Compliant Declaration
@property(weak) NSObject *parentObj;


<ARC 수식어 - 일반 변수>

변수 수식어

위의 예제들은 properties가 어떻게 관리 되어야 하는지 선언하는 것이었다. 일반 변수에 대해서는 아래와 같은 것들이 있다.

__strong
__weak
__unsafe_unretained
__autoreleasing

일반적으로 이러한 추가적인 qualifier들은 매우 자주 필요한 것은 아니다. 마이그레이션 툴을 사용했을 때 처음 볼 것이다. 하지만 새 프로젝트에서는 필요도 없고 대부분 properties선언에서 strong/weak를 쓸 것이다.

__strong - default 이며 타이핑 할 필요도 없다. 이 말은 어떤 객체가 alloc/init으로 생성되면 현재 scope의 일생동안 retain된다. 이 current scope 는 보통 변수가 선언되는 brace를 뜻한다. for block이나 if block같이

__weak - 이것은 언제든지 파괴될 수 있다는 뜻이다. 이것은 다른 strongly reference객체가 있을 때만 사용된다. 파괴되면 __weak 변수는 nil이 된다.

__unsafe_unretained - 이것은 __weak과 같지만 object가 해제 되어도 pointer가 nil로 되지 않는다. 대신 pointer가 여전히 메달려 있다.(하지만 유효하지는 않다)

__autoreleasing - method에서 반환하기 전에 객체에 autorelease를 호출하는 것과 햇갈리지 않으면서 오브젝트를 참조(reference)로 넘길 때 사용된다. 예를 들면 NSError objects를 참조방식으로 넘길 때 [myObject performOperationWithError:&tmp]; 쓴다.

Source: LLVM Clang Objective-C Automatic Reference Counting Documentation

NB: 우리는 @property 선언에서 ARC가 활성화 되어 있는데 strong대신 retain을 써도 컴파일러가 warning을 내지 않는 것을 발견했다. 하지만 미래에도 명확히 하기 위해 strong으로 써라.


<ARC로 기존 프로젝트 마이그레이션 하기>

Xcode 4.2에는 기존 코드를 ARC로 변환하기 위한 conversion tool을 제공한다. 그리고 자동으로 마이그레이션 못하는 코드를 수동으로 변환하는데 도움을 준다.

1. non-ARC 프로젝트를 열어서 Edit>Refactor>Convert to Objective-C ARC. 를 눌러라
06.png

2. 변환하고 싶은 build targets과 파일을 선택하라.
07.png

3. 미리 검사하기를 누르고 Next를 클릭
08.png

nb : next를 누르면 LLVM 컴파일러가 프로젝트를 분석할 것이다. 만약 프로젝트에 어떤 에러가 있으면  다음 과정으로 갈 수 없다. Xcode 새 버젼에서 처음 열었으면 Clean한번 해줘라.

4. 제안된 변화를 검사하고 포함할지 제외할지 고른다음 save 눌러라
09.png

NB : 어떤 파일은 마이그레이션 안되는 것을 알아야 한다, 모든 파일(라이브러리 포함)이 마이그레이션 될 필요는 없다. ARC는 개별 파일에 각각 설정할 수 있기 때문에 compile time에 제외하는 방법은 아래에서 설명한다.

5. 마이그레이션 툴이 자동으로 컴파일러 옵션을 켜준다. build setting에서 확인해봐라(검색어 : reference counting)


<ARC 컴파일 사용하지 않는 코드 포함하기>

애플 문서에서는 "ARC 방식은 수동 reference counting 코드를 파일 단위로 조절한다. 어떤 파일은 수동으로 하고 싶으면 그렇게 할 수 있다"고 한다

이 말은 어떤 파일은 ARC를 사용하고 어떤 파일은 사용하지 않을 수 있다는 말이다. 컴파일 타임에 ARC에서 제외시키는 절차를 설명한다.

이글을 쓰는 시점에에도 많은 유명한 라이브러리들이 ARC 준비가 안되어 있다. 아래 절차를 따라 해보자.

1. Xcode project tree를 클릭

2. Target을 클릭

3. Build Phases tab을 선택

4. Compile Sources section을 확장

5. ARC에서 제외하고 싶은 하나 또는 더 많은 파일을 선택

6. 엔터키를 한 번친다.

7. -fno-objc-arc 를 타이핑

8. 엔티키를 다시 친다.

9. 각각 파일은 이제 -fno-objc-arc 컴파일러 옵션이 켜졌고 ARC에서 제외될 것이다.


<그럼에도 불구하고 ARC를 써야하나?>

Objective-C를 처음 접한다면 써야한다. reference counted memory에 대한 걱정 없이 처음부터 배운다면 그것보다 좋은 것은 없다. 기존의 라이브러리를 사용하기 시작할 때 ARC pre-compilation을 확실히 제외하는 방법에 익숙해 지지 않으면 고통이…

ARC없이 행복하게 코딩하고 있었다면 아마 "난 필요없어!"라고 생각할 것이다. 지금까지 당신한테는 맞을 수도 있겠다. 대부분의 유명한 라이브러리들이 ARC로 변환되지 않았고 Core Foundation classes들도 ARC와 잘 동작하지 않는다. CF 클래스를 사용할때는 확실히 한계가 존재하고 toll free bridging을 동작하게 하려면 migrating code인 extra qualifiers들이 붙는다.

내가 보고 읽은 바로는 ARC는 바로 사용가능하다. 하지만 익숙해지기 전까지는 새 프로젝트에서만 사용하자. ARC가 iOS 4.0 에서 하위 호완성을 가지지만 weak reference는 iOS 5.0에서만 지원된다. 아마 다른 이유로 아직 모두 마이그레이션 안된 것 같다. (더 자세히 보려면 이 글 끝에 Resources 를 보시오)

어떤 초기 보고서는 ARC가 당신의 프로젝트를 더 빨리 만들 수 있다고 주장한다. 아마도 autorelease에 더 적은 신뢰로말이다. 하지만 retain/release를 더 잘 사용해서 할 수도 있다. 하지만 요점은 이것이다. ARC는 당신의 코드에서 효율적인 접근을 자동으로 선택해준다는 것.

현재 ARC로 옮기는 것은 조금은 힘들다. 긴 주말 뒤에 새 프로젝트를 시작할 때 이것은 애플의 새 추천 접근 방법이다. 그러니까 미래의 디자인 결정을 할 때 ARC 기반으로 하고 수동 reference counting을 하지 않게 될 것이다.

List of Articles
번호 제목 글쓴이 날짜 조회 수
21 Cocoa Programming 정리 08 - NSArrayController file Hojung 2013.02.25 5362
20 Cocoa Programming 정리 07 - Key-Value Coding 과 Key-Value Observing file Hojung 2013.02.20 4482
19 Cocoa Programming 정리 06 - 헬퍼 객체 file Hojung 2013.02.19 6827
18 Cocoa Programming 정리 05 - 타겟(Target)과 액션(Action) file Hojung 2013.02.14 5786
» Cocoa Programming 정리 04 - 메모리 관리 file Hojung 2013.02.13 5648
16 Cocoa Programming 정리 03 - Objective-C file Hojung 2013.02.08 5430
15 Cocoa Programming 정리 02 - 시작하기 file Hojung 2013.02.05 8024
14 Cocoa Programming 정리 01 - Cocoa란? Hojung 2013.02.05 4296
13 객체 변수 선언시 @private 사용 Hojung 2012.09.18 3725
12 테스트 코드 작성 Hojung 2012.08.22 3464
11 NSString 객체의 생성과 변환 Hojung 2012.08.22 4487
10 클래스 프로퍼티 설정 Hojung 2012.08.22 3500
9 클래스와 객체 - 1 Hojung 2012.08.22 3577
8 Interface and Implementation Hojung 2012.08.22 3330
7 Extends vs Implements의 개념과 차이점 - 2 Hojung 2012.08.22 3680
6 Extends vs Implements의 개념과 차이점 - 1 Hojung 2012.08.22 4271
5 포인터 Hojung 2012.08.22 3608
4 조건문 및 순환문 Hojung 2012.08.22 3747
3 변수형 및 객체형 Hojung 2012.08.22 3715
2 hello world Hojung 2012.08.22 3530
Board Pagination ‹ Prev 1 2 Next ›
/ 2

Designed by sketchbooks.co.kr / sketchbook5 board skin

나눔글꼴 설치 안내


이 PC에는 나눔글꼴이 설치되어 있지 않습니다.

이 사이트를 나눔글꼴로 보기 위해서는
나눔글꼴을 설치해야 합니다.

설치 취소

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5