ARC에서 @autore release 풀이 여전히 필요한 이유는 무엇입니까?
ARC(Automatic Reference Counting)를 사용하는 대부분의 경우 Objective-C 개체를 사용하는 메모리 관리에 대해 전혀 생각할 필요가 없습니다.생이허용않다습니지를 생성하는 것은 되지 않습니다.NSAutoreleasePool
하지만 더 이상 새로운 구문이 있습니다.
@autoreleasepool {
…
}
제 질문은 수동으로 릴리스/자동 릴리스할 필요가 없는데 왜 이 기능이 필요하냐는 것입니다.
편집: 모든 답변과 코멘트에서 얻은 내용을 요약하면 다음과 같습니다.
새 구문:
@autoreleasepool { … }
에 대한 새로운 구문입니다.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
…
[pool drain];
더 중요한 것은:
- 는 ARC 용을 합니다.
autorelease
만 아니라release
. - 이를 위해서는 자동 해제 풀이 필요합니다.
- ARC는 자동 릴리스 풀을 생성하지 않습니다.그러나:
- 모든 코코아 앱의 메인 스레드에는 이미 자동 릴리스 풀이 있습니다.
- 다음과 같은 두 가지 경우를 활용할 수 있습니다.
@autoreleasepool
:- 때 풀이 누출을 .
myRunLoop(…) { @autoreleasepool { … } return success; }
. - @mattjgallay가 답변에서 보여주었듯이, 더 로컬 풀을 만들고 싶을 때.
- 때 풀이 누출을 .
ARC는 보유, 릴리스 및 자동 릴리스를 제거하지 않고 필요한 항목만 추가합니다.따라서 아직 유지해야 할 요청이 있고, 해제해야 할 요청이 있으며, 자동 해제 요청이 있으며, 자동 해제 풀도 있습니다.
그들이 새로운 Clang 3.0 컴파일러와 ARC에서 한 다른 변경 사항 중 하나는 그들이 대체했다는 것입니다.NSAutoReleasePool
@autoreleasepool
컴파일러 지시문. NSAutoReleasePool
어쨌든 항상 약간의 특별한 "객체"였고 그들은 하나를 사용하는 구문이 객체와 혼동되지 않도록 만들어 일반적으로 조금 더 단순합니다.
그래서 기본적으로, 당신은 필요합니다.@autoreleasepool
걱정해야 할 자동 해제 풀이 아직 남아 있기 때문입니다.추가하는 것에 대해 걱정할 필요가 없습니다.autorelease
전화가 걸려오는 전화.
자동 릴리스 풀 사용 예:
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
@autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(@"number = %p", number);
}
}
}
}
아주 잘 고안된 예입니다, 물론, 하지만 만약 당신이 그것을 가지고 있지 않았다면.@autoreleasepool
에.for
를 한 돌 를 방출하게 .for
-루프.
업데이트: 이 답변도 참조하십시오. - https://stackoverflow.com/a/7950636/1068248 - 이유@autoreleasepool
ARC와는 아무런 관련이 없습니다.
업데이트: 여기서 무슨 일이 일어나고 있는지 내부를 살펴보고 블로그에 기록했습니다.ARC가 어떤 기능을 수행하고 있으며 새로운 스타일이 어떻게 적용되고 있는지 정확히 확인할 수 있습니다.@autoreleasepool
그리고 스코프를 도입하는 방법은 컴파일러가 보유, 릴리스 및 자동 릴리스가 필요한 항목에 대한 정보를 추론하는 데 사용됩니다.
@autoreleasepool
자동으로 아무것도 릴리스하지 않습니다.자동 해제 풀을 생성하여 블록의 끝에 도달하면 블록이 활성화된 동안 ARC에 의해 자동 해제된 모든 개체에 릴리스 메시지가 전송됩니다.Apple의 Advanced Memory Management Programming Guide는 다음과 같이 설명합니다.
자동 해제 풀 블록의 끝에서 블록 내에서 자동 해제 메시지를 받은 개체는 릴리스 메시지(블록 내에서 자동 해제 메시지를 보낼 때마다 개체가 릴리스 메시지를 받습니다.
사람들은 종종 ARC를 쓰레기 수거 같은 것으로 오해합니다.은 (프로젝트 에) 후 clang (allvm clang 로은분덕프트젝얼모를마의들및브사후)를 깨달았습니다.retains
그리고.releases
등)은 컴파일 시에 완전히 자동화될 수 있습니다.이것은 코드를 읽기만 해도 실행되기 전에! :)
그렇게 하기 위해서는 단 한 가지 조건이 있습니다.규칙을 따라야 합니다. 그렇지 않으면 컴파일러가 컴파일 시 프로세스를 자동화할 수 없습니다.그래서, 우리가 절대 규칙을 어기지 않도록 하기 위해, 우리는 명시적으로 글을 쓰는 것이 허용되지 않습니다.release
,retain
dll에 됩니다. 이러한 호출은 컴파일러에 의해 자동으로 코드에 주입됩니다.그러므로 내부적으로 우리는 여전히 가지고 있습니다.autorelease
s,retain
,release
쓸가 없을 입니다. ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅠ
ARC의 A는 컴파일 시 자동으로 실행되며 가비지 컬렉션과 같은 런타임보다 훨씬 우수합니다.
는 아직 직아있다니습이 .@autoreleasepool{...}
규칙을 위반하지 않기 때문에 필요할 때마다 언제든지 자유롭게 풀을 생성/해제할 수 있습니다 :).
메서드에서 새로 생성된 개체를 반환하려면 자동 릴리스 풀이 필요합니다.예를 들어 다음 코드를 고려합니다.
- (NSString *)messageOfTheDay {
return [[NSString alloc] initWithFormat:@"Hello %@!", self.username];
}
메소드에서 생성된 문자열의 유지 개수는 1입니다.이제 누가 그 숫자를 유지하는 것과 석방을 균형 있게 할 것입니까?
방법 자체?불가능합니다. 생성된 개체를 반환해야 하므로 반환 전에 개체를 해제하면 안 됩니다.
메소드의 호출자?호출자는 해제가 필요한 개체를 검색할 것으로 예상하지 않으며, 메서드 이름은 새 개체가 생성되었음을 의미하지 않으며, 개체가 반환되고 이 반환된 개체는 해제가 필요한 새 개체일 수 있지만 그렇지 않은 기존 개체일 수도 있습니다.메소드가 반환하는 내용은 일부 내부 상태에 따라 달라질 수 있으므로 호출자는 해당 개체를 해제해야 하는지 여부를 알 수 없고 관심을 가질 필요가 없습니다.
호출자가 항상 반환된 모든 개체를 규칙적으로 해제해야 하는 경우 새로 생성되지 않은 모든 개체는 메서드에서 반환되기 전에 항상 유지되어야 하며 다시 반환되지 않는 한 범위를 벗어나면 호출자가 해제해야 합니다.이는 대부분의 경우 호출자가 반환된 개체를 항상 해제하지 않을 경우 유지 횟수를 변경하는 것을 완전히 피할 수 있기 때문에 매우 비효율적입니다.
그렇기 때문에 자동 해제 풀이 있으므로 첫 번째 방법은 실제로
- (NSString *)messageOfTheDay {
NSString * res = [[NSString alloc] initWithFormat:@"Hello %@!", self.username];
return [res autorelease];
}
하기 르기autorelease
개체에서 자동 릴리스 풀에 개체를 추가합니다. 하지만 자동 릴리스 풀에 개체를 추가한다는 것은 실제로 무엇을 의미합니까?음, 그것은 당신의 시스템에 "나는 당신이 나를 위해 그 물체를 놓아주길 원하지만, 지금은 아니다; 그것은 방출에 의해 균형을 유지해야 하는 유지 카운트를 가지고 있다; 그렇지 않으면 메모리가 유출될 것이지만, 나는 그것을 지금 당장 할 수 없다, 왜냐하면 나는 물체가 내 현재 범위를 벗어나도록 필요하고 내 전화를 건 사람도 나를 위해 그것을 해주지 않을 것이기 때문이다. 이 작업이 수행되어야 한다는 것을 알지 못합니다. 따라서 수영장에 추가하고 수영장을 정리한 후에는 제 물건도 정리해 주십시오."
ARC를 사용하면 컴파일러가 개체를 유지할 시기, 개체를 릴리스할 시기 및 자동 릴리스 풀에 추가할 시기를 결정하지만 메모리 누수 없이 메서드에서 새로 생성된 개체를 반환할 수 있으려면 자동 릴리스 풀이 있어야 합니다.Apple은 생성된 코드를 몇 가지 최적화하여 런타임 중에 자동 릴리스 풀을 제거하기도 합니다.이러한 최적화를 위해서는 발신자와 착신자가 모두 ARC를 사용해야 합니다(ARC와 비 ARC를 혼합하는 것은 합법적이며 공식적으로도 지원됩니다). 실제로 그런 경우에는 런타임에만 알 수 있습니다.
다음 ARC 코드를 고려합니다.
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
시스템이 생성하는 코드는 다음 코드처럼 동작할 수 있습니다(ARC 코드와 비ARC 코드를 자유롭게 혼합할 수 있는 안전한 버전).
// Callee
- (SomeObject *)getSomeObject {
return [[[SomeObject alloc] init] autorelease];
}
// Caller
SomeObject * obj = [[self getSomeObject] retain];
[obj doStuff];
[obj release];
(호출자의 보유/해제는 방어적인 안전 보유일 뿐이며 엄격하게 요구되는 것은 아니며, 보유자가 없으면 코드가 완벽하게 정확합니다.)
또는 런타임에 둘 다 ARC를 사용하는 것으로 감지되는 경우 이 코드처럼 동작할 수 있습니다.
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
[obj release];
보시다시피 Apple은 튜어 릴리스를 제거하므로 풀이 파괴될 때 개체 릴리스가 지연되고 안전이 유지됩니다.그것이 어떻게 가능하고 실제로 배후에서 무슨 일이 일어나고 있는지에 대해 더 자세히 알아보려면 이 블로그 게시물을 확인하십시오.
이제 실제 질문으로 넘어갑니다. 사할이를 합니까?@autoreleasepool
?
대부분의 개발자들에게 오늘날 코드에서 이 구조를 사용하는 이유는 단 한 가지, 즉 해당하는 경우 메모리 설치 공간을 작게 유지하는 것입니다.예: 이 루프를 고려합니다.
for (int i = 0; i < 1000000; i++) {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
를 할때다마에 tempObjectForData
새생할수있을 할 수 있습니다.TempObject
자동 해제가 반환됩니다.에 모두 수집된 중 개를 됩니다.for-loop은 100개의 임시 개체를 합니다.그렇게 되기 전까지는 백만 개의 임시 개체가 메모리에 저장되어 있습니다.
대신 코드를 다음과 같이 작성하면 다음과 같습니다.
for (int i = 0; i < 1000000; i++) @autoreleasepool {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
그런 다음 for-loop이 실행될 때마다 새 풀이 생성되고 각 루프 반복이 끝날 때마다 폐기됩니다.그렇게 하면 루프가 백만 번 실행됨에도 불구하고 최대 한 개의 임시 개체가 언제든지 메모리에서 맴돌고 있습니다.
스레드를 할 때 관리해야 경우가 과는스레예때자풀릴직관했리야접습해다니도스리동거관할에리를드예s:▁in(했습다니ore▁yourself▁when▁(야e리해관▁autpool▁had▁manage▁often과접직▁to▁threads:NSThread
메인 스레드에만 Cocoa/UIKit 앱에 대한 자동 릴리스 풀이 자동으로 제공되기 때문입니다.하지만 오늘날 여러분은 아마도 처음부터 스레드를 사용하지 않을 것이기 때문에 이것은 꽤 많은 유산입니다.당신은 GCD를 사용할 것입니다.DispatchQueue
의 또는NSOperationQueue
이 두 가지는 모두 블록/작업을 실행하기 전에 생성되고 완료되면 삭제되는 최상위 자동 릴리스 풀을 관리합니다.
자동으로 릴리스된 개체가 범위를 벗어나는 것이 안전한 시점에 대한 힌트를 컴파일러에 제공해야 하기 때문입니다.
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html 에서 인용:
풀 블록 및 스레드 자동 해제
코코아 응용프로그램의 각 스레드는 자체 자동 해제 풀 블록 스택을 유지 관리합니다.Foundation 전용 프로그램을 작성하거나 스레드를 분리하는 경우 자체 자동 해제 풀 블록을 만들어야 합니다.
애플리케이션 또는 스레드가 수명이 길고 잠재적으로 많은 자동 릴리스 개체를 생성할 수 있는 경우에는 자동 릴리스 풀 블록(예: 메인 스레드에서 AppKit 및 UIKit)을 사용해야 합니다. 그렇지 않으면 자동 릴리스 개체가 누적되고 메모리 공간이 증가합니다.분리된 스레드가 코코아를 호출하지 않는 경우 자동 해제 풀 블록을 사용할 필요가 없습니다.
참고: NSTread 대신 POSIX 스레드 API를 사용하여 보조 스레드를 생성하는 경우, 코코아가 멀티 스레드 모드에 있지 않으면 코코아를 사용할 수 없습니다.코코아는 첫 번째 NST 스레드 개체를 분리한 후에만 멀티 스레드 모드로 전환됩니다.보조 POSIX 스레드에서 코코아를 사용하려면 응용 프로그램이 먼저 하나 이상의 NST 스레드 개체를 분리해야 하며, 이 개체는 즉시 종료될 수 있습니다.NSTread 클래스 메소드가 MultiThread인 상태에서 코코아가 멀티스레딩 모드에 있는지 테스트할 수 있습니다.
...
자동 참조 카운팅(ARC)에서 시스템은 MRR과 동일한 참조 카운팅 시스템을 사용하지만 컴파일 시 적절한 메모리 관리 방법을 삽입합니다.새로운 프로젝트에 ARC를 사용하는 것이 좋습니다.ARC를 사용하는 경우에는 일반적으로 이 문서에 설명된 기본 구현을 이해할 필요가 없지만 상황에 따라 유용할 수도 있습니다.ARC에 대한 자세한 내용은 ARC 릴리스 정보로 전환을 참조하십시오.
TL;DR
ARC에서 @autore release 풀이 여전히 필요한 이유는 무엇입니까?
@autoreleasepool
및에서 Objective-C 스위프트와 하는 데 됩니다.autorelese
의 내부의
순수 Swift로 작업하고 Swift 객체를 할당하는 경우 - ARC가 처리합니다.
하지만 통화/사용하기로 결정한 경우Foundation/Legacy Objective-C code
(NSData
,Data
을 사용하는 것입니다.autorelese
당시의 그당에 안에.@autoreleasepool
//Swift
let imageData = try! Data(contentsOf: url)
//Data init uses Objective-C code with [NSData dataWithContentsOfURL] which uses `autorelese`
긴 대답
MRC, ARC, GC
Manual Reference Counting(MRC)
또는Manual Retain-Release(MRR)
를 수동으로 세는 이 있습니다.
Automatic Reference Counting(ARC)
iOS v5.0 및 OS X Mountain Lion과 xCode v4.2에 도입되었습니다.
Garbage Collection(GC)
는 Mac OS에서 사용할 수 있으며 OS X Mountain Lion에서는 더 이상 사용되지 않습니다.ARCARC로.
MRC 및 ARC 기준 카운트
//MRC
NSLog(@"Retain Count: %d", [variable retainCount]);
//ARC
NSLog(@"Retain Count: %ld", CFGetRetainCount((__bridge CFTypeRef) variable));
힙의 모든 개체에는 해당 개체에서 가리키는 참조 수를 나타내는 정수 값이 있습니다.0과 같을 경우 시스템에서 개체의 할당이 해제됩니다.
- 개체 할당
- 참조 개수로 작업
- 개체 할당 취소 중입니다.
deinit
다음과 같은 경우에 호출됩니다.retainCount == 0
MRC
A *a1 = [[A alloc] init]; //this A object retainCount = 1
A *a2 = a1;
[a2 retain]; //this A object retainCount = 2
// a1, a2 -> object in heap with retainCount
올바른 개체 해제 방법:
release
이것뿐이라면 - 달링 포인터. 수 수 입니다.= nil
이에만 - 을 - .deinit라고 부르지 .
A *a = [[A alloc] init]; //++retainCount = 1
[a release]; //--retainCount = 0
a = nil; //guarantees that even somebody else has a reference to the object, and we try to send some message thought variable `a` this message will be just skipped
참조 수 작업(개체 소유자 규칙):
- (0 -> 1)
alloc
,new
,copy
,mutableCopy
- (+1)
retain
은 필요한할 수 .retain
번 - (-1)
release
소유자인 경우 반드시 해제해야 합니다.하면 retainCount 0이 . - (-1)
autorelease
해야 할 에추다니가개합체를에 합니다.autorelease pool
이 풀은 [정보]RunLoop 반복 주기가 끝날 때(스택에서 모든 작업이 완료될 때를 의미함) 처리됩니다.release
됩니다. - (-1)
@autoreleasepool
블록 끝에서 자동 해제 풀을 강제로 처리합니다.그것은 당신이 처리할 때 사용됩니다.autorelease
가능한 한 빨리 리소스를 삭제하고 싶습니다.을 하지 않는다면 해서 증가할 입니다.
autorelease
는 새 할 때 됩니다.
- (B *)foo {
B *b1 = [[B alloc] init]; //retainCount = 1
//fix - correct way - add it to fix wrong way
//[b1 autorelease];
//wrong way(without fix)
return b;
}
- (void)testFoo {
B *b2 = [a foo];
[b2 retain]; //retainCount = 2
//some logic
[b2 release]; //retainCount = 1
//Memory Leak
}
@autoreleasepool
를 들어보기
- (void)testFoo {
for(i=0; i<100; i++) {
B *b2 = [a foo];
//process b2
}
}
ARC
중이하의 큰 중 .ARC
으로 자으로삽것입다를 삽입하는 것입니다.retain
,release
,autorelease
컴파일 타임의 후드 아래에서 그리고 개발자로서 당신은 그것을 더 이상 처리하지 말아야 합니다.
ARC 활성화/비활성화
//enable
-fobjc-arc
//disable
-fno-objc-arc
우선순위가 높은 것부터 낮은 것까지 다양성
//1. local file - most priority
Build Phases -> Compile Sources -> Compiler Flags(Select files -> Enter)
//2. global
Build Settings -> Other C Flags(OTHER_CFLAGS)
//3. global
Build Settings -> Objective-C Automatic Reference Counting(CLANG_ENABLE_OBJC_ARC)
ARC가 활성화/비활성화되었는지 확인합니다.
Preprocessor
__has_feature
함수가 사용됩니다.
__has_feature(objc_arc)
컴파일 시간
// error if ARC is Off. Force to enable ARC
#if ! __has_feature(objc_arc)
#error Please enable ARC for this file
#endif
//or
// error if ARC is On. Force to disable ARC
#if __has_feature(objc_arc)
#error Please disable ARC for this file
#endif
런타임
#if __has_feature(objc_arc)
// ARC is On
NSLog(@"ARC on");
#else
// ARC is Off
NSLog(@"ARC off");
#endif
리버스 엔지니어링(Objective-C의 경우)
//ARC is enabled
otool -I -v <binary_path> | grep "<mrc_message>"
//e.g.
otool -I -v "/Users/alex/ARC_experiments.app/ARC_experiments" | grep "_objc_release"
//result
0x00000001000080e0 748 _objc_release
//<mrc_message>
_objc_retain
_objc_release
_objc_autoreleaseReturnValue
_objc_retainAutoreleaseReturnValue
_objc_retainAutoreleasedReturnValue
_objc_storeStrong
목표 CMRC를 ARC로 마이그레이션하는 도구
으로 ARC를 제거해야 오류를 합니다.retain
,release
,autorelease
이슈들은
Edit -> Convert -> To Objective-C ARC...
MRC가 포함된 새 X 코드
MRC를 활성화하면 다음 오류(경고)가 표시됩니다(그러나 빌드는 성공합니다).
//release/retain/autorelease/retainCount
'release' is unavailable: not available in automatic reference counting mode
ARC forbids explicit message send of 'release'
이 주제에 대해 많은 혼란이 있는 것 같습니다(그리고 아마도 지금 이 문제에 대해 혼란스러워하고 자신의 코드 주변에 @autoreleasepool을 뿌릴 필요가 있다고 생각하는 최소 80명의 사람들).
프로젝트(그 종속성 포함)가 ARC만을 사용하는 경우 @autorereleasepool은 사용할 필요가 없으며 유용한 작업을 수행하지 않습니다. ARC는 올바른 시간에 객체를 릴리스하는 작업을 처리합니다.예:
@interface Testing: NSObject
+ (void) test;
@end
@implementation Testing
- (void) dealloc { NSLog(@"dealloc"); }
+ (void) test
{
while(true) NSLog(@"p = %p", [Testing new]);
}
@end
디스플레이:
p = 0x17696f80
dealloc
p = 0x17570a90
dealloc
각 테스트 개체는 자동 릴리스 풀이 종료될 때까지 기다리지 않고 값이 범위를 벗어나는 즉시 할당이 해제됩니다.(NSNumber 예제에서도 동일한 현상이 발생합니다. 이를 통해 할당 해제를 확인할 수 있습니다.) ARC는 자동 릴리스를 사용하지 않습니다.
@autorereleasepool이 여전히 허용되는 이유는 아직 ARC로 완전히 전환되지 않은 ARC와 비 ARC 프로젝트가 혼합되어 있기 때문입니다.
비 ARC 코드를 호출하면 자동으로 릴리스된 개체가 반환될 수 있습니다.이 경우 현재 자동 해제 풀이 종료되지 않으므로 위의 루프가 누출됩니다.여기서 코드 블록 주위에 @autore release 풀을 배치할 수 있습니다.
그러나 ARC를 완전히 전환한 경우에는 자동 해제 풀을 사용하지 마십시오.
언급URL : https://stackoverflow.com/questions/9086913/why-is-autoreleasepool-still-needed-with-arc
'source' 카테고리의 다른 글
VBA에 대한 권장 IDE (0) | 2023.05.27 |
---|---|
MC의 기능:무시할 수 있는="d"는 WPF로 표시됩니까? (0) | 2023.05.27 |
Xcode 및 SDK 4+를 사용하여 fat 정적 라이브러리(장치 + 시뮬레이터) 구축 (0) | 2023.05.27 |
"max_connections"와 같은 매개 변수(postgresql.conf 설정)를 쿼리합니다. (0) | 2023.05.22 |
불투명 컨트롤이 포함된 투명 배경의 WPF 창 (0) | 2023.05.22 |