ObjectiveC NSAutoreleasePool

From 흡혈양파의 인터넷工房
Jump to navigation Jump to search
간편하지만 독이되어버리는 NSAutoreleasePool

출처
http://b4you.net/blog/208


iPhone 개발을 하며 NSAutoreleasePool 클래스를 보게 되는데, 이 클래스의 역할은 autorelease가 설정되어 있는 객체들을 pool이 release될 때 덩달아 release해줍니다. NSAutoreleasePool은 다음 기회에 c++이나 Java로 비슷하게 만들어 보기로 하고..-ㅁ-


여기서는 이 NSAutoreleasePool 때문에 깔끔하지 못한 코드가 나오는 것을 보겠습니다.


예) 문자열을 리턴해야 되는 메서드가 있습니다. 이 문자열을 어떻게 리턴 해주어야 할까요?


기존의 C 방식에서는 다음과 같이 합니다. (예제를 간단하게 만드느라 유니코드는 생략합니다)

void getChars(char *p, int len)
{
    strncpy(p, "hello~!", len);
}
 
int main()
{
    char *a;
    a = (char *)malloc(sizeof(char) * 100);
    getChars(a, 100);
    printf("%s", a);
    return 0;
}


메모리 할당 후 return해줘도 되지만... 보통은 위와 같이 하죠.

이걸 Objective-C의 NS* 시리즈로 autorelease를 이용해서 구현 한다면?

- (NSString *)getChars
{
    return [NSString stringWithFormat:"hello~!"];
}

와 비슷하게 됩니다. (당.연.히 위의 C코드와는 다릅니다)


중요한건 이게 언젠간 autorelease pool에 의해 release가 되는데.. pool이 release 될 때까지 기다려야 된다는 것 입니다. 그러면 pool이 release 되기 전까지는 쭈욱 메모리를 차지 하고 있는데... (이 부분이 background에서 알아서 release 해주는 garbage collector와 다른점이 되겠습니다) 이걸 개발자가 수동으로 release 하게끔 짜놓으면 만사 OK지만... 문제는 기존에 autorelease로 짜놓은 코드들이 너무 많다는 것 입니다. 즉 autorelease를 남발해댄(NSString의 stringWithFormat와 같은) 소스를 쓰면 릭 아닌 릭(?)이 발생한다 이거죠.


이런걸 해결하려면 일정 구간을 또 다른 NSAutoreleasePool로 묶을 수 있습니다. 다음과 같이 말이죠

// 1차 autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
for(int i = 0; i < 100000; i++)
{
    // pool이 담당하는 autorelease 구간
    // autorelease #1
    [NSString stringWithFormat:@"autorelease test"];
}
 
sleep(5);
 
// 2차 autorelease pool
NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
 
for(int i = 0; i < 100000; i++)
{
    // pool2가 담당하는 autorelease 구간
    // autorelease #2
    [NSString stringWithFormat:@"autorelease test"];
}
 
// autorelease #2 영역의 데이터 정리
[pool2 release];
 
sleep(5);
 
[pool release];


이렇게 nested(?) autorelease pool을 사용하면 다음과 같이 할당 됩니다.

1396096881.png


초반에 열심히 할당하고 5초 지난 후 또다시 열심히 할당하고 그다음에 반으로 깎이는 것을 보실 수 있습니다.

이렇게 사용할 수 있지만.. 잘못 사용하면 독이 된다는거~!!