preface

Autorelease Apple documentation

  • Autorelease Pools provides a mechanism to delay sending release messages to objects. It avoids when you want to relinquish ownership of an object but don’t want to release it right away (such as when you return an object from a method).

  • For example, when we create an object and put it into the automatic release pool, it will not be released immediately, but will wait until a runloop ends or the scope is out of {}.

Relationship between Autoreleasepool and Runloop

  • The main thread of theNSRunLoopEach time the event response is detected to openevent loopPreviously, one was created automaticallyautorelease poolAnd will be inevent loopExecute at the enddrainAction to release the object
  • If our program creates a large number of temporary variables, we canAutoreleasepoolTo reduce memory spikes.

Relationship between Autoreleasepool and threads

  • Each thread, including the main thread, maintains its own auto-free pool stack structure
  • [Fixed] New auto-release pools are added to the top of the stack when created. It is removed from the stack when the autofree pool is destroyed
  • For the current thread, the auto-free object is placed at the top of the auto-free pool stack; When a thread stops, all automatic release pools associated with that thread are automatically released

Clang analysis

Create a new project as follows:

Enter themain.mFor the directory where the file resides, enterclang -rewrite-objc main.m -o main.cppWill generate ac++file

  • @autoreleasepoolThe bottom layer is a structure
  • in{}Is called in scopeobjc_autoreleasePoolPush()Constructor sumobjc_autoreleasePoolPop()The destructor

Continue adding a symbolic breakpoint for objc_autoreleasePoolPush: find the source code implementation in objC

Autoreleasepool structure analysis

Open objC source code, search for objc_autoreleasePoolPush,

Found that calledAutoreleasePoolPageThe inside of the classpushMethod, when we analyze the source code do not rush to see, we should first to understand the underlying structure.

Structure analysis

AutoreleasePoolPage inherits from AutoreleasePoolPageData

  • magic: Used to detectAutoreleasePoolPageIs the structure complete, occupying 16 bits
  • next: indicates the latest additionautoreleasedObject at the next location to which it points when initializedbegin(), occupying 8 bits
  • thread: refers to the current thread // occupies 8 bits
  • parent: refers to the parent node, the first nodeparentA value ofnilTake up eight
  • child: refers to the child node, the last nodechildA value ofnilTake up eight
  • depth: represents depth, from0Start and increase1Take up to four
  • hiwat: The maximum number of pushmarks occupies 4 bits

Understand the structure through comments

  • one-threadautorealse poolIt’s a bunch of Pointers
  • There are two types of pointer: the object to be released and the POOL_BOUNDARY. The boundary tells us whether the page object has been deleted.
  • The collection structure of this pointer is actually oneDouble linked list structure. Pages are related to each other.
  • The current thread stores locally the hot page object that points to the newly automatically released hot page

Adding an Object process

autoreleaseFast

Called in non-bug modeautoreleaseFast

autoreleaseFastcall

  • ifpageStored in and not full, directly inpageAfter adding
  • ifpageFull of callautoreleaseFullPage
  • If there is nopagecallautoreleaseNoPage

AutoreleaseNoPage process

  • Create a new page and set it to HotPage
  • forpageaddPOOL_BOUNDARYThe border
  • pageAdd an obj object, a page can be viewed as a single linked list,page->addThis is equivalent to adding an obj object to the end of the list.

AutoreleaseFullPage process

  • So this is essentially finding the end of the double-linked listpage, exit the loop,pageAdd the correspondingobj

The size of the page

There is a macro definition in the source code

  • So a page size is 1<<12, which is 4096.

  • But how many objects can a page store? , page itself attribute size = magic+next+ Thread +parent+ Child +depth+hiwat = 56, if the home page also has a boundary object POOL_BOUNDARY occupies 8 bytes.

  • So first page, objcCount = (4096-56-8) /8 = 504,

  • If it’s not the home page with no boundaries, it’s 505 objects

Verify page size

_objc_autoreleasePoolPrintYou can print the page information with 506 local variables generated as follows

  • There are two pages, the first page is full with 504 objects, and the second page has two

AutoreleasePool nested

Curious what the structure of the page looks like if AutoreleasePool is nested, do the following test

View the print result:

  • When the first automatic release poolpageWhen the pool is not full, objects from the nested auto-release pool continue to be added later.
  • Whenever you create an auto-release pool, a boundary object is created.

Automatic release pool release

call_objc_autoreleasePoolPopmethods popThe key method is calledpopPageThe rest of the code is debug related and does not affect the main flowEnter the popPage

releaseUntil

The key method is to call the Page ->releaseUntil method and repeatedly call objC_Release (obj) to send a release message to obJ.

  • It’s pretty easy to implement with onewhileCyclic continuous releaseAutoreleasePoolPageUntilnextPoints to thestop
  • usememsetSet the contents of memory toSCRIBBLEAnd then useobjc_releaseRelease the object.

conclusion

Here’s another diagram to summarize the auto-release pool, because graphics are more memorable.