IT박스

Cocoa 및 Objective-C를 사용한 참조 횟수 이해

itboxs 2020. 7. 11. 11:08
반응형

Cocoa 및 Objective-C를 사용한 참조 횟수 이해


방금 Objective-C와 Cocoa를 살펴보고 iPhone SDK로 게임을 볼 수 있습니다. 나는 C mallocfree개념에 합리적으로 편안 하지만 Cocoa의 참조 계산 체계는 다소 혼란 스럽습니다. 일단 당신이 그것을 이해하면 매우 우아하다고 들었지만, 나는 아직 고비가 아닙니다.

어떻게 release, retain그리고 autorelease작업과 그 사용에 대한 규칙은 무엇인가?

(또는 그것을 실패하면, 무엇을 얻었습니까?


retainand로 시작하자 release. autorelease기본 개념을 이해하면 실제로는 특별한 경우입니다.

Cocoa에서 각 객체는 참조되는 횟수를 추적합니다 (특히 NSObject기본 클래스가이를 구현 함). retain객체 를 호출 하면 참조 횟수를 1 씩 늘리겠다고 알려줍니다. 을 호출 release하면 객체에서 객체를 제거하고 참조 횟수가 감소합니다. 를 호출 한 후 release참조 카운트가 이제 0이면 해당 객체의 메모리가 시스템에 의해 해제됩니다.

기본적인 방법이 다르다 mallocfree특정 개체가 그들이 사용하던 메모리를 해제했기 때문에 충돌 시스템의 다른 부분에 대해 걱정할 필요가 없다는 것입니다. 모든 사람이 규칙에 따라 재생 및 유지 / 해제한다고 가정하면, 한 코드 조각이 개체를 유지 한 다음 해제 할 때 개체를 참조하는 다른 코드 조각은 영향을받지 않습니다.

무엇 때때로 혼동 할 수있는 것은 당신이 호출 할 필요가있는 상황을 알고있다 retainrelease. 일반적인 경험 규칙은 일정 기간 동안 객체에 매달리고 싶다면 (예를 들어 클래스의 멤버 변수 인 경우) 객체의 참조 횟수가 나에 대해 알고 있어야한다는 것입니다. 위에서 설명한 것처럼 객체의 참조 카운트는을 호출하여 증가합니다 retain. 관례 상, "init"메소드로 객체를 생성 할 때도 증가합니다 (실제로 1로 설정 됨). 이 두 가지 경우에, release내가 끝났을 때 객체 를 호출하는 것은 나의 책임 입니다. 그렇지 않으면 메모리 누수가 발생합니다.

객체 생성의 예 :

NSString* s = [[NSString alloc] init];  // Ref count is 1
[s retain];                             // Ref count is 2 - silly
                                        //   to do this after init
[s release];                            // Ref count is back to 1
[s release];                            // Ref count is 0, object is freed

지금은 autorelease. Autorelease는 시스템이이 오브젝트를 잠시 후에 해제하도록하는 편리한 (때로는 필요한) 방법으로 사용됩니다. 배관 관점에서 autorelease호출하면 현재 스레드 NSAutoreleasePool에 호출이 경고됩니다. NSAutoreleasePool이제 (이벤트 루프의 현재 반복 후) 기회를 얻으면,이 호출 할 수있는 것을 알고 release개체에. 프로그래머로서 우리의 관점에서 볼 때 우리는 전화 release를 필요로하므로 돌릴 필요가 없습니다 (실제로해서는 안됩니다).

중요한 것은 모든 객체 생성 클래스 메소드가 자동 릴리스 된 객체를 반환한다는 것입니다. 예를 들어 다음 예에서 변수 "s"의 참조 카운트는 1이지만 이벤트 루프가 완료된 후에는 소멸됩니다.

NSString* s = [NSString stringWithString:@"Hello World"];

해당 문자열에 매 달리려면 retain명시 적으로 호출 한 다음 release완료되면 명시 적으로 호출해야합니다 .

다음과 같은 (매우 고안된) 비트 코드를 고려하면 autorelease필요한 상황이 나타납니다 .

- (NSString*)createHelloWorldString
{
    NSString* s = [[NSString alloc] initWithString:@"Hello World"];

    // Now what?  We want to return s, but we've upped its reference count.
    // The caller shouldn't be responsible for releasing it, since we're the
    // ones that created it.  If we call release, however, the reference 
    // count will hit zero and bad memory will be returned to the caller.  
    // The answer is to call autorelease before returning the string.  By 
    // explicitly calling autorelease, we pass the responsibility for
    // releasing the string on to the thread's NSAutoreleasePool, which will
    // happen at some later time.  The consequence is that the returned string 
    // will still be valid for the caller of this function.
    return [s autorelease];
}

나는이 모든 것이 약간 혼란 스럽다는 것을 알고 있습니다. 그러나 언젠가는 클릭합니다. 다음은 참고 자료입니다.

  • 메모리 관리에 대한 Apple의 소개 .
  • Aaron Hillegas가 작성한 Mac OS X 용 Cocoa Programming (4 판) – 훌륭한 예제가 많이 들어있는 매우 잘 쓰여진 책. 튜토리얼처럼 읽습니다.
  • 실제로 다이빙을하고 있다면 Big Nerd Ranch로 향할 수 있습니다. 이것은 위에서 언급 한 책의 저자 인 Aaron Hillegas가 운영하는 훈련 시설입니다. 몇 년 전에 코코아 인트로 코스에 다녔는데, 배우는 좋은 방법이었습니다.

유지 / 해제 과정을 이해한다면, 코코아 프로그래머에게는 "두"라는 명백한 두 가지 황금 규칙이 있지만, 불행히도 이민자들에게는이 규칙을 명확하게 설명하는 경우는 거의 없습니다.

  1. 객체를 반환하는 함수가있는 경우 alloc, create또는 copy이름에 다음 개체는 당신입니다. [object release]완료되면 전화해야 합니다. 또는 CFRelease(object)Core-Foundation 객체 인 경우.

  2. 이름에 이러한 단어 중 하나가 없으면 개체는 다른 사람의 것입니다. [object retain]함수 종료 후 객체를 유지 하려면 호출해야합니다 .

자신을 만드는 기능에서이 규칙을 따르는 것이 좋습니다.

(Nitpickers : 그렇습니다. 불행히도이 규칙에는 예외이지만 거의 드물게 몇 가지 API 호출이 있습니다.)


If you're writing code for the desktop and you can target Mac OS X 10.5, you should at least look into using Objective-C garbage collection. It really will simplify most of your development — that's why Apple put all the effort into creating it in the first place, and making it perform well.

As for the memory management rules when not using GC:

  • If you create a new object using +alloc/+allocWithZone:, +new, -copy or -mutableCopy or if you -retain an object, you are taking ownership of it and must ensure it is sent -release.
  • If you receive an object in any other way, you are not the owner of it and should not ensure it is sent -release.
  • If you want to make sure an object is sent -release you can either send that yourself, or you can send the object -autorelease and the current autorelease pool will send it -release (once per received -autorelease) when the pool is drained.

Typically -autorelease is used as a way of ensuring that objects live for the length of the current event, but are cleaned up afterwards, as there is an autorelease pool that surrounds Cocoa's event processing. In Cocoa, it is far more common to return objects to a caller that are autoreleased than it is to return objets that the caller itself needs to release.


Objective-C uses Reference Counting, which means each Object has a reference count. When an object is created, it has a reference count of "1". Simply speaking, when an object is referred to (ie, stored somewhere), it gets "retained" which means its reference count is increased by one. When an object is no longer needed, it is "released" which means its reference count is decreased by one.

When an object's reference count is 0, the object is freed. This is basic reference counting.

For some languages, references are automatically increased and decreased, but objective-c is not one of those languages. Thus the programmer is responsible for retaining and releasing.

A typical way to write a method is:

id myVar = [someObject someMessage];
.... do something ....;
[myVar release];
return someValue;

The problem of needing to remember to release any acquired resources inside of code is both tedious and error-prone. Objective-C introduces another concept aimed at making this much easier: Autorelease Pools. Autorelease pools are special objects that are installed on each thread. They are a fairly simple class, if you look up NSAutoreleasePool.

When an object gets an "autorelease" message sent to it, the object will look for any autorelease pools sitting on the stack for this current thread. It will add the object to the list as an object to send a "release" message to at some point in the future, which is generally when the pool itself is released.

Taking the code above, you can rewrite it to be shorter and easier to read by saying:

id myVar = [[someObject someMessage] autorelease];
... do something ...;
return someValue;

Because the object is autoreleased, we no longer need to explicitly call "release" on it. This is because we know some autorelease pool will do it for us later.

Hopefully this helps. The Wikipedia article is pretty good about reference counting. More information about autorelease pools can be found here. Also note that if you are building for Mac OS X 10.5 and later, you can tell Xcode to build with garbage collection enabled, allowing you to completely ignore retain/release/autorelease.


Joshua (#6591) - The Garbage collection stuff in Mac OS X 10.5 seems pretty cool, but isn't available for the iPhone (or if you want your app to run on pre-10.5 versions of Mac OS X).

Also, if you're writing a library or something that might be reused, using the GC mode locks anyone using the code into also using the GC mode, so as I understand it, anyone trying to write widely reusable code tends to go for managing memory manually.


As ever, when people start trying to re-word the reference material they almost invariably get something wrong or provide an incomplete description.

Apple provides a complete description of Cocoa's memory management system in Memory Management Programming Guide for Cocoa, at the end of which there is a brief but accurate summary of the Memory Management Rules.


I'll not add to the specific of retain/release other than you might want to think about dropping $50 and getting the Hillegass book, but I would strongly suggest getting into using the Instruments tools very early in the development of your application (even your first one!). To do so, Run->Start with performance tools. I'd start with Leaks which is just one of many of the instruments available but will help to show you when you've forgot to release. It's quit daunting how much information you'll be presented with. But check out this tutorial to get up and going fast:
COCOA TUTORIAL: FIXING MEMORY LEAKS WITH INSTRUMENTS

Actually trying to force leaks might be a better way of, in turn, learning how to prevent them! Good luck ;)


Matt Dillard wrote:

return [[s autorelease] release];

Autorelease does not retain the object. Autorelease simply puts it in queue to be released later. You do not want to have a release statement there.


My usual collection of Cocoa memory management articles:

cocoa memory management


There's a free screencast available from the iDeveloperTV Network

Memory Management in Objective-C


NilObject's answer is a good start. Here's some supplemental info pertaining to manual memory management (required on the iPhone).

If you personally alloc/init an object, it comes with a reference count of 1. You are responsible for cleaning up after it when it's no longer needed, either by calling [foo release] or [foo autorelease]. release cleans it up right away, whereas autorelease adds the object to the autorelease pool, which will automatically release it at a later time.

autorelease is primarily for when you have a method that needs to return the object in question (so you can't manually release it, else you'll be returning a nil object) but you don't want to hold on to it, either.

If you acquire an object where you did not call alloc/init to get it -- for example:

foo = [NSString stringWithString:@"hello"];

but you want to hang on to this object, you need to call [foo retain]. Otherwise, it's possible it will get autoreleased and you'll be holding on to a nil reference (as it would in the above stringWithString example). When you no longer need it, call [foo release].


The answers above give clear restatements of what the documentation says; the problem most new people run into is the undocumented cases. For example:

  • Autorelease: docs say it will trigger a release "at some point in the future." WHEN?! Basically, you can count on the object being around until you exit your code back into the system event loop. The system MAY release the object any time after the current event cycle. (I think Matt said that, earlier.)

  • Static strings: NSString *foo = @"bar"; -- do you have to retain or release that? No. How about

    -(void)getBar {
        return @"bar";
    }
    

    ...

    NSString *foo = [self getBar]; // still no need to retain or release
    
  • The Creation Rule: If you created it, you own it, and are expected to release it.

In general, the way new Cocoa programmers get messed up is by not understanding which routines return an object with a retainCount > 0.

Here is a snippet from Very Simple Rules For Memory Management In Cocoa:

Retention Count rules

  • Within a given block, the use of -copy, -alloc and -retain should equal the use of -release and -autorelease.
  • Objects created using convenience constructors (e.g. NSString's stringWithString) are considered autoreleased.
  • Implement a -dealloc method to release the instancevariables you own

The 1st bullet says: if you called alloc (or new fooCopy), you need to call release on that object.

The 2nd bullet says: if you use a convenience constructor and you need the object to hang around (as with an image to be drawn later), you need to retain (and then later release) it.

The 3rd should be self-explanatory.


Lots of good information on cocoadev too:


As several people mentioned already, Apple's Intro to Memory Management is by far the best place to start.

아직 언급하지 않은 유용한 링크 중 하나는 Practical Memory Management 입니다. Apple 문서를 읽으면 Apple 문서 중간에 있지만 직접 연결하는 것이 좋습니다. 예와 일반적인 실수 (기본적으로 다른 답변이 설명하려고하지만 그렇지 않은 경우)와 함께 메모리 관리 규칙을 훌륭하게 요약 한 것입니다.

참고 URL : https://stackoverflow.com/questions/6578/understanding-reference-counting-with-cocoa-and-objective-c

반응형