NSAutoreleasePool 자동 릴리스 풀은 어떻게 작동합니까?
-
09-06-2019 - |
문제
내가 이해하는 바에 따르면, 할당, 새로운, 또는 복사 수동으로 해제해야 합니다.예를 들어:
int main(void) {
NSString *string;
string = [[NSString alloc] init];
/* use the string */
[string release];
}
하지만 내 질문은 이것이 타당하지 않을까 하는 것입니다.
int main(void) {
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
[pool drain];
}
해결책
예, 두 번째 코드 조각은 완벽하게 유효합니다.
-autorelease가 객체로 전송될 때마다 가장 안쪽의 자동 릴리스 풀에 추가됩니다.풀이 비워지면 풀의 모든 개체에 -release를 보냅니다.
자동 릴리스 풀은 단순히 "나중에"까지 릴리스 전송을 연기할 수 있는 편의를 제공합니다."나중에"는 여러 위치에서 발생할 수 있지만 Cocoa GUI 앱에서 가장 일반적인 것은 현재 실행 루프 주기가 끝날 때입니다.
다른 팁
NSAutorelease풀:배수 대풀어 주다
의 기능부터 drain
그리고 release
혼란을 야기하는 것 같으니 여기에서 명확히 하는 것이 좋습니다. 문서...).
엄밀히 말하면 큰 그림의 관점에서 보면 drain
~이다 ~ 아니다 에 해당 release
:
참조 계산 환경에서는 drain
와 동일한 작업을 수행합니다. release
, 따라서 두 개는 그런 의미에서 동일합니다.강조하자면, 이는 다음을 의미합니다. ~ 아니다 사용하는 경우 수영장 누출 drain
오히려 release
.
가비지 수집 환경에서는 release
작동하지 않습니다.따라서 효과가 없습니다. drain
, 반면에 "필요한 경우 수집해야 한다"는 힌트가 수집기에 포함되어 있습니다.따라서 가비지 수집 환경에서는 다음을 사용합니다. drain
시스템 균형 수집을 돕습니다.
이미 지적했듯이 두 번째 코드 조각은 정확합니다.
나는 모든 환경(참조 계산, GC, ARC)에서 작동하고 배수/릴리스 혼란을 피하는 자동 릴리스 풀을 사용하는 보다 간결한 방법을 제안하고 싶습니다.
int main(void) {
@autoreleasepool {
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
}
}
위의 예에서 다음 사항에 유의하세요. @autoreleasepool 차단하다.이것은 문서화되어 있습니다. 여기.
아니, 넌 틀렸어.문서에는 GC가 아닌 경우 -drain이 -release와 동일하다고 명시되어 있습니다. 즉, NSAutoreleasePool은 ~ 아니다 유출되다.
내가 Apple에서 읽은 내용은 다음과 같습니다."자동 해제 풀 블록이 끝나면 블록 내에서 자동 해제 메시지를 받은 객체에 해제 메시지가 전송됩니다. 객체는 블록 내에서 자동 해제 메시지가 전송될 때마다 해제 메시지를 받습니다."
객체에 릴리스 대신 자동 릴리스를 보내면 적어도 풀 자체가 비워질 때까지 해당 객체의 수명이 연장됩니다(객체가 이후에 유지되는 경우 더 길어질 수 있음).객체는 동일한 풀에 여러 번 들어갈 수 있으며, 이 경우 풀에 들어갈 때마다 해제 메시지를 받습니다.
예, 아니오.가비지 수집(메모리 관리 아님) 환경에서 이 작업을 실행한 경우 릴리스 대신 드레인을 사용하여 문자열 메모리를 해제하지만 NSAutoreleasePool 개체를 메모리로 "누출"하게 됩니다.이 "누출"은 단순히 GC 아래에 강력한 포인터가 없는 다른 개체처럼 NSAutoreleasePool의 인스턴스를 "접근할 수 없게" 만들고 다음 번에 GC가 실행될 때 개체가 정리됩니다. 이는 호출 직후일 수 있습니다. -drain
:
물을 빼다
가비지 수집 환경에서 마지막 수집 이후 할당된 메모리가 현재 임계값보다 큰 경우 가비지 수집을 트리거합니다.그렇지 않으면 릴리스로 동작합니다....가비지 수집 환경에서 이 메서드는 궁극적으로 다음을 호출합니다.
objc_collect_if_needed
.
그렇지 않으면 방법과 비슷합니다. -release
GC가 아닌 경우에도 작동합니다. 그렇습니다.다른 사람들이 말했듯이, -release
GC에서는 작동하지 않으므로 GC에서 풀이 제대로 작동하는지 확인하는 유일한 방법은 다음과 같습니다. -drain
, 그리고 -drain
비 GC에서는 다음과 똑같이 작동합니다. -release
GC가 아닌 경우에도 그 기능을 더 명확하게 전달합니다.
"new, alloc 또는 init로 호출되는 모든 것"이라는 명령문에는 "init"가 포함되어서는 안 됩니다(그러나 "복사"는 포함되어야 함). "init"는 메모리를 할당하지 않고 객체(생성자)만 설정하기 때문입니다. 패션).할당된 객체를 받았고 함수가 init만 호출했다면 해당 객체를 해제하지 않을 것입니다.
- (void)func:(NSObject*)allocd_but_not_init
{
[allocd_but_not_init init];
}
이는 이미 시작한 것보다 더 많은 메모리를 소비하지 않습니다(init가 객체를 인스턴스화하지 않는다고 가정하지만 어쨌든 이에 대한 책임은 없습니다).