why is autoreleasepool releasing objects that were retained?!

Hello! I'm using Core ML to do some machine learning predictions.

It seems that I have to put the call to "predictionWithFeatures" in an autoreleasepool block, otherwise it will leak memory like crazy. (This is in a project with ARC turned off.)

I need to be able to use the results of the prediction outside of the function that does the predictions.

So, no problem, I just 'retain' the object that gets returned, right? Except that the autoreleasepool seems to free the object even though its retain count is 3. (Aside: why is it 3?)

If anybody can tell me why the autoreleasepool block is freeing objects that have been retained, I would greatly appreciate it. Thank you!

Pseudocode below...

myCoreMLModelOutput *outputGlobal = NULL;

void DoPredictions()
{
	if (outputGlobal != NULL) {
		[outputGlobal release];
		outputGlobal = NULL;
	}
	...
	@autoreleasepool {  // necessary to prevent predictionFromFeatures from leaking memory
		outputGlobal = [myCoreMLModel predictionFromFeatures ...];
		[outputGlobal retain];  // need to be able to access this later
		printf("retain count: %d\n", (int)[outputGlobal retainCount]);  // why is this 3 and not 1 or 2?
	}
	DoSomethingWithOutputGlobal();  // crashes ... why was outputGlobal released?!
}

Answered by DTS Engineer in 726349022

(Aside: why is it 3?)

The value returned by retainCount is never easy to understand. I generally recommend that you avoid looking at it. A better way to understand this stuff is with the Allocations instrument, which shows retains, releases, and autoreleases and also has smarts to match them up.

otherwise it will leak memory like crazy.

Leak? You seem to be using terms is a non-standard way. In Apple parlance a leak is memory that can’t ever be freed. If the autorelease pool is freeing it then it wasn’t leaked, it was just building up in the autorelease pool.

Still, that doesn’t explain the crash you’re seeing. If you run with zombies, does DoSomethingWithOutputGlobal trigger a zombie?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer

(Aside: why is it 3?)

The value returned by retainCount is never easy to understand. I generally recommend that you avoid looking at it. A better way to understand this stuff is with the Allocations instrument, which shows retains, releases, and autoreleases and also has smarts to match them up.

otherwise it will leak memory like crazy.

Leak? You seem to be using terms is a non-standard way. In Apple parlance a leak is memory that can’t ever be freed. If the autorelease pool is freeing it then it wasn’t leaked, it was just building up in the autorelease pool.

Still, that doesn’t explain the crash you’re seeing. If you run with zombies, does DoSomethingWithOutputGlobal trigger a zombie?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you for your reply. It sent me in the right direction. I was able to figure out that my output object was actually being retained as intended, but its constituent data (two MLMultiArray member variables) were being freed. I didn't realize that's how things worked. I've been able to solve the problem by calling retain on the MLMultiArrays. Thanks again.

You're also right that I was using the term "leak" the wrong way. I'm working on a command line program and it doesn't have an event loop. So NSObjects don't get freed unless I do something to manually free them. I didn't really understand that last night but I've been learning.

I was able to figure out that my output object was actually being retained as intended, but its constituent data (two MLMultiArray member variables) were being freed. I didn't realize that's how things worked.

That depends on how you declare and then store the value:

  • If you declare the value as an ivar, or you use a property but store the value directly to the ivar, then, yep, you have to manually retain (or copy) it.

  • If you declare the value as a property and store using property syntax, you don’t (assuming you have declare the property using retain or copy).

This assumes you’re using manual retain/release (MRR). If you use automatic reference counting (ARC) this whole problem goes away.

Why are you using MRR? Most folks writing new code use ARC. It makes everything much easier.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I'm using the code for my Core ML model that's automatically generated by XCode. The files say not to modify them at the top, and the files themselves seem to be stored outside of my project, so I'm not sure if any modifications would even persist. So, the MLMultiArray member variables are declared the way they're declared.

As for ARC, I've never used it before and I wasn't sure it would give me the behavior I wanted. (How would it know when to free the output of the prediction?)

I'm using the code for my Core ML model that's automatically generated by Xcode.

I’m not familiar with that process, but my best guess is that this code was generated assuming that you have ARC enabled. That’s been the default for… well… probably about a decade.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

why is autoreleasepool releasing objects that were retained?!
 
 
Q