Objective-c memory management - how long is the existence of an object guaranteed?

I have an ARC code like this:

NSMutableData* someData = [NSMutableData dataWithLength:123]; ...

CTRunGetGlyphs(run, CGRangeMake(0, 0), someData.mutableBytes); ...

const CGGlyph *glyphs = [someData mutableBytes]; ...

... then code that reads memory from glyphs but does nothing with someData that is no longer referenced. Please note: CGGlyph is not an object type, but an unsigned integer.

Do I have to worry about the memory in someData being freed before I finish using glyphs (which is actually just pointing inside someData )?

All this code is in the same scope (i.e. one selector), and glyphs and someData go out of someData at the same time.

PS In an earlier draft of this question, I mentioned "garbage collection", which is really not applicable to my project. That's why some of the answers below give him an equal relationship with what happens with ARC.

+4
source share
4 answers

Starting in the summer of 2012, everything happens during the change process for Apple objects that return internal pointers of a type other than the object. In the notes for Mountain Lion, Apple says:

NS_RETURNS_INNER_POINTER

Methods that return pointers (except for the Objective-C object type) were decorated with the clang objc_returns_inner_pointer compiler attribute (when compiling with clang) to prevent the compiler from aggressively freeing the recipient expression of these messages that are no longer referenced, while the returned pointer may still used.

Checking the NSData.h header file shows that this also applies to iOS 6.

Also note that NS_RETURNS_INNER_POINTER is defined as __attribute__((objc_returns_inner_pointer)) in the clang specification, which makes it such that

the lifetime of the object will be extended to at least the earliest of: the last use of the returned pointer or any pointer obtained from it in the calling function; or the resource pool is restored to its previous state.

Caveats: If you are using something older than Mountain Lion or iOS 6, you will still have to use any of the methods described here (e.g. __attribute__((objc_precise_lifetime)) ) when declaring local NSData or NSMutableData objects.

In addition, even with the latest Apple compilers and libraries, if you use old or third-party libraries with objects that do not decorate their return methods with __attribute__((objc_returns_inner_pointer)) , you will need to decorate local variable declarations of such objects with __attribute__((objc_precise_lifetime)) or use one of the other methods discussed in the answers.

+1
source

You are potentially having trouble using GC or, as others have recommended, ARC instead. What you are dealing with is an internal pointer that is not considered a listing link in GC or ARC at all - unless the implementation has special NSData covers. Without this ownership, a GC or ARC link can delete an object. The problem you are facing is peculiar to internal pointers.

As you describe your situation, the safest thing is to hang on a real link. You can do this by assigning the NSData reference to either the instance variable or the static variable (local method, if you want), and then assign nil this variable when you are done with the internal pointer. In case of static be careful with concurrency!

In practice, your code will probably work in both GC and ARC, probably more likely in ARC, but maybe you can bite you, especially when the compilers change. For the cost of one variable declaration and one additional task, you avoid the problem, cheap insurance.

[Cm. this discussion is an example of a short life span in ARC.]

+4
source

In real, real garbage collection, this code could potentially be a problem. Objects can be freed as soon as they are no more, and the compiler can refuse the link at any time if you will never use it again. For optimization purposes, an area is just a way to impose an upper limit on such a thing, rather than dictating it absolutely.

You can use NSAllocateCollectable to bind life cycle calculations to C primitive pointers, although it's messy and slightly confusing.

Garbage collection has never been implemented on iOS and is now deprecated on Mac (as indicated at the bottom of this FAQ ), in both cases in favor of automatic link counting (ARC). ARC adds retain and releases , where it can see that they are implicitly needed. Unfortunately, it can perform some neat tricks that were not previously possible, for example, retrieving objects from the startup pool if they were used as the return results. Thus, it has the same net effect as the garbage collection approach - an object can be released at any time after the final link to it disappears.

A workaround would be to create a class like:

 @interface PFDoNothing + (void)doNothingWith:(id)object; @end 

What is implemented to do nothing. Submit your auto-implemented object after you finish using the internal memory. Objective-C dynamic dispatch means that the compiler is unsafe to optimize the call - it does not know that you (or the KVO mechanisms or any other actor) did not do something like the swizzle method at runtime.

EDIT: NSData is a special case because it offers direct C-level access to object-oriented memory, and it is easy to find an explicit discussion of the situation with GC. See this thread on Cocoabuilder for a pretty good one, although the same caution applies as above, that is, garbage collection is outdated, and automatic link counting works differently.

+3
source

The following is a generic answer that does not necessarily reflect support for the Objective-C GC. However, various GC implementations, including ref-counting, can be considered in terms of reachability, quirks to the side.


In the GC language, the existence of an object is guaranteed as long as it is Strongly Achievable ; the "roots" of these Strong-Reachability graphs may vary depending on the language and runtime. The exact meaning of Strong is also changing, but generally means that the edges are Strong links. (In the manual recalculation scenario, each edge can be considered as an unsurpassed "save" from this "owner".)

C # on CLR / .NET is one such implementation where a variable can remain in scope and still not work as the β€œroot” for the reachability graph. See the Systems.Timer.Timer Class and find GC.KeepAlive :

If a timer is declared in a long-term method, use KeepAlive to prevent garbage collection [on the timer object] until the method completes.

+2
source

Source: https://habr.com/ru/post/1434277/


All Articles