Objective-c and swift's memory management methods are based on reference counting "reference counting". Reference counting is a simple and effective way to manage the life cycle of objects.Reference counting is divided into manual reference counting "arc:automatic reference counting" and automatic reference counting "mrc:manual reference counting". Now both use arc, but it is still necessary to understand mrc.

1. What is the principle of reference counting?

When we create a new object,His citation count is 1;

When there is a new pointer to this object,His citation count is incremented by one;

When an object's associated pointer no longer points to him,His citation count is decremented by one;

When the reference count of an object is 0, it means that the object is no longer pointed by any pointer.Then we can destroy the object,Reclaim memory.

Because reference counting is simple and effective,In addition to the objective-c language, Microsoft's com "component object model", c++ 11 (reference pointer based smart pointer share_prt) and other languages ​​also provide reference count based memory management.

for example:

New Construction,Xcode has Arc turned on by default. Here we use mrc for the "appdelegate.m" file and perform the following configuration:

Select the target project,Then configure the compiler parameter `` compiler flags '' value in the `` appdelegate.m '' file under `` compile sources '' in `` build phases '' as `` -fno-objc-arc ''

-(bool) application:(uiapplication *) application didfinishlaunchingwithoptions:(nsdictionary *) launchoptions {
  nsobject * objo=[nsobject new];
  nslog (@ "reference count:%lu", (unsigned long) [objo retaincount]);//1
  nsobject * objb=[objo retain];
  nslog (@ "reference count:%lu", (unsigned long) [objo retaincount]);//2
  [objo release];
  nslog (@ "reference count:%lu", (unsigned long) [objo retaincount]);//1
  [objo release];
  nslog (@ "reference count:%lu", (unsigned long) [objo retaincount]);//1
  [objo setvalue:nil forkey:@"test"];//zombie object,Sending a message to a wild pointer will report an error (exc_bad_access)
  return yes;

xcode does not monitor zombie objects by default,Here we configure to enable him,Then you can see the specific tracking information:

You can also open the "instruments" toolset by selecting "profile" under "product". Then select "zombies" and click the "choose" button in the lower right corner to enter the detection interface,At this point, click the "record" red dot button in the upper left corner to start detection.

1.1 The above example,Why the last value obtained by retaincount was 1 instead of 0?

Because the object's memory has been reclaimed,We send a retaincount message to a recycled object, and its output is uncertain.If the memory occupied by the object is reused,Then it may cause the program to crash abnormally.

And when the last execution of the release, the system already knew that it was about to reclaim memory,There is no need to decrement retaincount by 1, because the object will be recycled no matter if it is decremented,After collection, the memory area (including retaincount value) is no longer meaningful.Without reducing retaincount by 1 to 0, you can reduce one memory operation,Speed ​​up the recycling of objects.

1.2 What are zombie objects, wild pointers, and null pointers?

Zombie object:an object whose memory has been recycled,Zombie objects can no longer be used.

Wild pointer:A pointer to a zombie object (unavailable memory). Sending a message to the wild pointer will report an error (exc_bad_access).

Null pointer:There is no pointer to any object (storage is nil, null). Sending a message to the null pointer will not report an error;A classic use case of the null pointer is to convert the wild pointer to a null pointer when obtaining server api data in development.Avoid sending errors.

2. Why do you need reference counting?

From the simple example above,We still don't see the real use of reference counting,Because the life cycle of the object is only within a method.In real application scenarios,We use temporary objects within methods,It is usually not necessary to modify his reference count,Just destroy the object before the method returns.

However, the scenario where reference counting really comes in handy is in object-oriented programming architecture,Used to pass and share data between objects.

for example:

If object a generates an object o, a method of object b needs to be called.Pass object o as a parameter.

Without reference counting,The general principle of memory management is "who applies for release", then object a needs to destroy object o when object b no longer needs object o. But object b may use object o temporarily, or he may think he is important,Set him as a member variable of his own,under these circumstances,When to destroy the object o becomes a problem.

There are two approaches to the above situation:

(1) Object a After calling a method of object b,The parameter object o is destroyed immediately, and then object b needs to make a copy of object o,Generate another object o2 and manage the life cycle of object o2 yourself.But this approach has a big problem,That is, he brings more memory application, copy, and release work.Objects that could be reused,Because it is inconvenient to manage his life cycle,Simply destroy him,And reconstruct a copy of the same,It really affects performance too much.

(2) Object a is only responsible for generating object o, and then object b is responsible for completing the destruction of object o.If object b only uses object o temporarily, it can be destroyed immediately after use.If object b needs to use object o for a long time, it is not destroyed.This approach seems to solve the problem of object replication,But he relies heavily on the cooperation of two objects, a and b,Code maintainers need to remember this programming convention explicitly.Moreover, since the generation and release of object o are in different objects,Making his memory management code scattered across different objects,It is also laborious to manage.If the situation is more complicated at this time,For example, object b needs to pass parameter object o to object c, then this object cannot be managed by object c in object c. So this method brings more complexity,Even more undesirable.

The advent of reference counting solves this problem very well,During the transfer of the parameter object o,Which objects need to use him for a long time,Just increase his citation count by one and decrement it by one. All subjects adhere to this rule,The lifecycle management of the object can be completely handed over to reference counting.We can also easily enjoy the benefits brought by shared objects.

2.1 What is the "reference cycles" problem and how can I solve it?

Although reference counting is a simple memory management method,But one flaw is that he can't automatically solve the problem of circular references.

for example:

Object a and object b refer to each other as their member variables,Only when you destroy it yourself,Before decrementing the reference count of its member variable by 1, because the destruction of object a and object b are interdependent,This causes what we call a circular reference problem.

Circular references will cause them to be accessed even if no pointers can access them anymore,But they still cannot release the resources they occupy.

There are two main ways to solve the problem of circular references:

(1) Know exactly where there are circular references,Actively disconnect a reference in the ring at a reasonable time,Allows objects to be recycled.This method is not commonly used,Because he relies on the developer to manually control it explicitly,It is equivalent to returning to the previous era of "who applied for and released" memory management.

(2) Use weak reference "weak reference", "weak" "__weak" type, this method is commonly used.Although weak references hold objects,But it does not increase his reference count.A classic use case for weak references is the "delegate" protocol model of proxy.

2.2 Are there any tools in xcode that can detect circular references?

The "instruments" toolset in xcode makes it easy to detect circular references.

for example:

-(void) viewdidload {
  [super viewdidload];
  nsmutablearray * marrfirst=[nsmutablearray array];
  nsmutablearray * marrsecond=[nsmutablearray array];
  [marrfirst addobject:marrsecond];
  [marrsecond addobject:marrfirst];

You can select "profile" under "product" to open the "instruments" toolset.

Then select "leaks" and click the "choose" button in the lower right corner to enter the detection interfaceAt this point, click the "record" red dot button in the upper left corner to start detection.

3. memory management of core foundation objects

arc is a compiler feature,It is not a runtime feature,Not even the garbage collector "gc".

arc can solve 90%of memory management problems in ios development,But the other 10%of memory management issues need to be addressed by developers themselves.This is mainly the part that interacts with the underlying core foundation object,The underlying core foundation object is not under the management of arc,So you need to maintain the reference count of these objects yourself.

In fact, the cfretain and cfrelease methods used by core foundation objects can be considered equivalent to the retain and release methods of objective-c objects.So we can do similar management in mrc way.

3.1 In arc, how can I convert a core foundation object to an objective-c object?

The process of conversion,It's actually telling the compiler,How to adjust the object's reference count.

Here we can use the keyword "bridge" to do the conversion.Here is a description of these (double underscore) keywords:

(1) __bridge:only type conversion,Does not modify the reference count of related objects,When the original core foundation object is not in use,You need to call the cfrelease method.

(2) __bridge_retained:After type conversion,Increase the reference count of related objects by 1. When the original core foundation object is not in use,You need to call the cfrelease method.

(3) __bridge_transfer:After type conversion,Handle the reference count of related objects to arc management. When the original core foundation object is not in use,There is no need to call the cfrelease method.

According to specific business logic,Make good use of the three conversion keywords above.You can solve the problem of relative conversion between core foundation objects and objective-c objects.

  • Previous Example of recursive commission scheme implemented by PHP
  • Next Example of PHP's sprintf function based on JS
  • Trends