·您现在的位置: 江北区云翼计算机软件开发服务部 >> 文章中心 >> 网站建设 >> app软件开发 >> IOS开发 >> Objective-CMemoryManagement内存管理2

Objective-CMemoryManagement内存管理2

作者:佚名      IOS开发编辑:admin      更新时间:2022-07-23

Objective-C Memory Management 内存管理  2 

2.1 The Rules of Cocoa Memory Management

内存管理规则

(1)When you create an object using new, alloc, or copy, the object has a
retain count of 1. You are responsible for sending the object a release or autorelease message when you're finished with it. That way, it gets cleaned up when its useful life is over.

当你通过new,alloc,copy获得一个对象时,retain count是1 。你需要负责该对象的释放或被自动释放。

(2)When you get hold of an object via any other mechanism, assume it has
a retain count of 1 and that it has already been autoreleased. You don't need to do any further work to make sure it gets cleaned up. If you're going to hang on to the object for any length of time, retain it and make sure to release it when you're finished.

当你通过其他方式获得一个对象时,假设该对象 retain count 是1,并且已经自动释放,那么你不需要做别的工作。 当你需要保持这个对象任意长时间的时候,你应该retain 它,当你不用的时候要确保释放它。

(3)If you retain an object, you need to (eventually) release or autorelease it. Balance these retains and releases.

当你retain 一个对象时,你最终需要release或autorelease 它。

 

Whenever you get hold of an object, you must be aware of two things: how you got it and how long you plan on hanging on to it

当你获得一个对象时,你必须明白你怎么获得的和你打算用它多长时间。 

2.2 Transient Object 

Let's take a look at some common memory-management life cycle scenarios.

让我们看一些内存管理的场景。

(1)如果你只是短暂的拥有对象,通过alloc ,copy ,new 你应该安排释放。

NSMutableArray *array;

array = [[NSMutableArray alloc] init]; // count: 1

// use the array

[array release]; // count: 0

(2)如果对象通过其他机制,则你不需要担心释放的问题。

NSMutableArray *array;

array = [NSMutableArray arrayWithCapacity: 17];

// count: 1, autoreleased

// use the array

 

arrayWithCapacity: is not alloc, new, or copy, so you can assume that the object being returned has a retain count of 1 and has already been autoreleased. When the autorelease pool goes away, array is sent the release message; its retain count goes to 0, and its memory is recycled.

arraywithcapacity 不是通过alloc ,new ,or copy 获得的,所以你能假设该对象被返回一个retain count 为1,并且被自动释放了。当自动释放池释放了,那就会发送一个消息让你释放。

 

NSColor *color;

color = [NSColor blueColor];

// use the color

blueColor不是通过alloc,new,copy获得的,所以你应该假设retain count 为1,并且自动释放。

blueColor returns a global singleton object—a single object that's shared by every PRogram that needs it—and won't actually ever get destroyed, but you don't need to worry about those implementation details. All you need to know is that you do not need to explicitly release color.

当然blueColor 返回一个全局单例对象,一个对象被整个程序使用的。所以它不需要被释放,但是你不需要了解这些细节,只要明白你不需要明确地释放就行了。

2.3 Hanging on to Objects 

Frequently, you'll want to keep an object around for more than a couple of lines of code.

你经常需要保持一个对象不仅仅一些行。 

 

If you're getting an object from init, new, or copy, you don't need to do anything special. The object's retain count will be 1, so it will stick around. Just be sure to release the object in the dealloc method of the owner-object that's hanging on to it:

当你是通过init,new,copy得到的,那么你不需要做特别的事情。

只需要在delloc 方法中,释放就行了。

- (void) doStuff

{

 // flonkArray is an instance variable

 flonkArray = [NSMutableArray new]; // count: 1

} // doStuff

- (void) dealloc

{

 [flonkArray release]; // count: 0

 [super dealloc];

} // dealloc

 

If you get an object from something other than init, new, or copy, you need to remember to retain it.

当一个对象不是来自new,init,or copy ,你应该记住retain 它。

When you're writing a GUI application, think in event loops. You want to retain autoreleased objects that will survive for longer than the current event loop.

当在一个GUI application,想event loops。你想retain autoreleased 对象,比当前的events loops 生存时间更长。

- (void) doStuff

{

 // flonkArray is an instance variable

 flonkArray = [NSMutableArray arrayWithCapacity: 17];

 // count: 1, autoreleased

 [flonkArray retain]; // count: 2, 1 autorelease

} // doStuff

- (void) dealloc

{

 [flonkArray release]; // count: 0

 [super dealloc];

} // dealloc

If we didn't have retain in doStuff, flonkArray would get destroyed unexpectedly.

如果我们不retain doStuff,那么flonkArray可能destroyed 不可预期。 

Remember that the autorelease pool is purged at well-defined times: when it's explicitly destroyed in your own code or at the end of the event loop when using the AppKit.

autorelease pool清空在预定好的时间:当明确指明时和在event loop 结束时。

2.4 Automatic memory management, also called garbage collection 自动内存管理 垃圾回收机制

像java 和python 也有垃圾回收。

只有mac应用可以用垃圾回收

但是垃圾回收机制是可选的。

Just go to the Build Settings of the project information window, and choose Required [-fobjc-gc-only]

去 Build Settings  选择[-fobjc-gc-only].

这个好像在xcode5 已经不存在了。并且ios一直没有垃圾回收机制。

就当了解了。

2.5 Auotmatic Reference Counting  自动引用计数

What's the deal with no garbage collection in iOS? The main argument against garbage collection in iOS is that you don't know exactly when the garbage collector is going to show up.

iOS没有用垃圾回收机制,一个重要原因是用garbage collector时,你不确定什么时候出现垃圾回收。

Users don't want to have a game or phone call pause while the system cleans up memory.

用户不想再玩游戏或打电话的时候系统清理内存。

苹果想出了一个办法:atuomatic reference counting (ARC).

As the name suggests, ARC keeps track of your objects and decides which ones you meant to keep and which ones you didn't. It's a little like having a butler or personal assistant in your memory management.

ARC 跟踪你的对象,决定那个要保持,那个要取消。就像一个你的内存的私人助理。

When you use ARC, you allocate and use objects as you would normally, and the compiler inserts the retains and releases for you – you don't put them in yourself.

当你用arc时,你只需要用对象即可。编译器将添加或删除retain 和release信息。

ARC is not a garbage collector. As we've already discussed, garbage collection does its work at runtime, via code that runs and checks your objects periodically. In contrast, ARC does its thing at compile time.

ARC 不是垃圾回收机制。垃圾回收机制发生在运行时,而arc 发生在编译时。

It inserts the proper retains and releases, so memory management happens as it would in well-written manually managed code.

编译时插入适当的retain 和release,因此,内存管理因为很好地自动填充代码。

ARC is an opt-in feature, which means you must explicitly enable or disable it.

ARC 是个opt-in的特色,可供选择的特性。

ARC only works with retainable object pointers (ROPs). There are three kinds of retainable object pointers:

当然,arc 只能识别retainable object pointers 。

. 1)  Block pointers 

. 2)  Objective-C object pointers 

. 3)  Typedefs marked with __attribute__((NSObject)) 

All other pointer types, such as char * and CF objects such as CFStringRef, are not ARC compatible.

所有其他的指针像char * 和CFStringRef 不能和arc。

If you want to use ARC in your code, you must meet three requirements:

如果想用arc需要满足一下:
(1)You must be able to reliably identify which objects are to be managed. 

你必须明确地知道那个对象需要被管理。

(2)You must be able to indicate how to manage an object.

你需要指示怎样管理一个对象。
(3)You must have a reliable way of passing ownership of an object.

你需要明确地传递对一个对象的拥有关系。

The first requirement means that a root-level object of collections of objects must know how to manage its child objects.

第一个要求是说你必须知道一个容器的根对象如何管理它的子对象。

For example, let's say you have an array of strings created with malloc:

NSString **myString;

myString = malloc(10 * sizeof(NSString *));

This code creates a C array that points to ten strings. Because C arrays are not retainable, you can't use ARC on this structure.

这个代码创建了一个c array指向10个strings,但是c arrays不能被retainable。所以不能用arc。

第二要要求:This requirement usually means you must be able to increment and decrement the retain count on an object, which pretty much means anything that is derived from NSObject is cool.

你必须能增加或减少retain count。也就是说源于NSObject 的事情是很好的。

The third requirement states that when passing around an object, your program needs to be able to pass ownership of the object between the caller and the callee

第三个要求是当传送对象时,你的程序需要能够传递一个对象的拥有关系在调用和被调用间。 

 

2.6 Sometimes  weak is good  弱引用

If you manage the memory of an object, you're said to have a strong reference to the object. If you are not managing its memory, you have (you guessed it) a weak reference.

当你管理一个对象的内存时,你有一个强的引用。如果你不管理,你就有一个弱的引用。 

you have an object A that was created by some other object and has a retain count
of 1。

Object A creates an object B as its child, and object B has a retain count of 1

In this example, object A has a strong reference to Object B, because object A created object B. Now, if object B gets a strong reference to object A, the retain count on Object A increases to 2

这个时候,如果对象b有一个强 的引用对对象A,那么对象A 的retain count 增加了2 。

Eventually, the owner of object A no longer needs it. The owner calls

release on Object A, which decrements its retain count to 1.

最终拥有者不想再拥有A了,那么就应该释放A,那么A的retain count 成为了1.

But object B, which was created by object A, owns that 1 retain count. Because both objects have nonzero retain counts, neither of them is released. This is a classic memory leak: the program has no access to the objects, but they're still using memory

这个时候没有对象引用A,因为这两个对象都不是retain count 为0 ,所以这边是典型的memory leak 内存泄露:程序没有存储到对象,但是他们仍然在内存中。

 

为了解决这个问题,我们通过分配得到B对对象A的引用。使用weak reference ,retain count 不增加了。

So when object A's owner releases it, its retain count goes to zero, it releases B, and both A and B relinquish their precious memory

这很好,但是还不够,假如有三个对象,你不再用A了,并且有个强引用到B,并且C有一个弱引用到C,

如果A释放了B,C仍然有个weak reference ,但是不在valid。再使用可能引起崩溃。 

Here's the solution: objects that automagically clean up their weak references. These special weak references are called zeroing weak references, because when the object they point to is released, they are set to zero (nil) and can be handled like any other nil pointer

解决办法是:对象自动清理weak references。这些特殊的weak reference称为 zeroing weak references,因为当他们指向的对象为被释放的时候,那么他们也就指向了zero(nil)了。

 

To use zeroing weak references, you have to explicitly declare them.

你必须明确指明你要使用zero weak reference 。

There are two ways to declare zeroing weak references: by using the __weak keyWord when declaring a variable, or by using the weak attribute on properties:

__weak NSString *myString;

@property(weak) NSString *myString;

Apple provides the __unsafe_unretained keyword and unsafe_unretained attribute, both of which tell ARC that the specified reference is weak.

apple 还提供了__unsafe_unretained关键字和unsafe_unretained属性当指明arc 指定的reference是弱引用。

there is also a __strong keyword and strong attribute.

__strong和strong attribute 是强引用。

 

记住关键字和属性(key 和attribute是互斥的)

 

2.7  A new convertible 将原有项目转成ARC 

Xcode provides a handy procedure to convert our existing projects to ARC.
Xcode 提供了方便的程序把我们存在的工序转化成ARC的。
Before we start, we must make sure garbage collection is not turned on; garbage collection and ARC don't mix.
垃圾回收和ARC 不兼容。
ARC是单向的。一旦转成ARC,就不能转回来了。
(1)To start the process, select the target you want to convert, then choose Edit Refactor Convert to Objective-C ARC
 
(2)Next, you'll see a list of targets to convert (see Figure 9-15). If your target depends on other targets, you can choose to do this process in baby steps.
If you have some files that are shared among different projects and you don't want to convert those, you can select just the ones you want.
如果你有一些不想转成arc,那么可以不选。 



2.8  Ownership has its privileges 
One of the requirements we discussed earlier is that pointers in ARC code must be retainable object pointers (ROPs).
ARC 的一个要求就是指针必须是retainable object pointers (ROPs).
NSString *theString = @"Learn Objective-C";
CFStringRef cfString = (CFStringRef)theString;
One pointer, theString, is an ROP, while the other, CFStringRef, is not.
theString 是一个ROP(retainable object pointers),而CFStringRef 不是。
For a happy ARC experience, we need to tell the compiler who owns the pointer. To do this, we can use a C technique called a bridged cast.
为了能够使用ARC,我们必须告诉编译器谁拥有指针。为了这么我们使用C的技术 桥接(bridged cast)
This is a standard C type cast, but with extra keywords: __bridge, __bridge_retained, or __bridge_transfer.
这是标准的c 类型映射,但是要用关键字_bridge,_bridge_retained,or _birdge_transfer.
(1)(__bridge Type) Operand: This type of cast transfers a pointer but does not transfer its ownership.
转变了指针,但是并没有转变自身。
In our example above, the operand is theString, and Type is CFStringRef. When using this keyword, one pointer is a ROP, and the other is not. With this cast, ownership of the pointer stays with the operand. Here's how our example would look with this case:
          cfString = (__bridge CFStringRef)theString;
          cfString gets the assignment, but ownership stays with theString.
(2)(__bridge_retained Type) operand: In this type, ownership is transferred to the non-ROP.One pointer is an ROP, and the other is not.
在这个情况下所有权被转移到non-ROP.一个指针是ROP,另一个不是。
This cast increments the object's retain count, so you have to decrement it, just as with standard old-fashioned memory management.
你应该用古老的方式管理内存。 
cfString = (__bridge_retained CFStringRef)theString
In this case, cfString string owns the pointer and its retain count is incremented.
You're responsible for managing it with retain/release.
(3)(__bridge_transfer Type) operand: This cast does the opposite of the previous kind; it transfers ownership to the ROP. In this case, ARC owns the object and will ensure it's released like any other ARC object.
在这种情况下,它转变ownership 到ROP.

Another restriction is that structs and unions can't have ROPs as members, so code like this is not allowed:
另一个限制是:structs 和unions 不能有ROPs,因此下面的不对。
// Bad code. Do not steal or sell.
struct {
  int32_t foo;
  char *bar;
  NSString *baz;
} MyStruct;
You can get around this requirement by using a void * and a bridged cast. To assign and get the string back, our code would look like this:
你可以想下面这样使用
struct {
  int32_t foo;
  char *bar;
  void *baz;
} MyStruct;
MyStruct.baz = (__bridge_retained void *)theString;
NSString *myString = (__bridge_transfer NSString *)MyStruct.baz;

下面是一些方法,你不能调用在ARC 管理对象上。
retain
retainCount
release
autorelease
dealloc
There are also methods you're not permitted to override on ARC objects:
有以下方法不能被override 在ARC对象中
retain
retainCount
release

autorelease