日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[objective-c] 08 - 内存管理

發布時間:2023/12/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [objective-c] 08 - 内存管理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

OC語言中的內存管理機制為ARC(Automatic Reference Counting,自動引用計數)。于2011年中旬推出,替換陳舊且低效的手動內存管理,關于手動內存管理的內容,本章教程不再講授。本章主要從以下幾個方面對內存管理進行展開講解。

  • 內存管理原則
  • 對象引用類型
  • 屬性引用類型
  • 強引用循環
  • AUTO類型與釋放池

1.內存管理原則

核心原則:沒有被對象指針使用(指向)的內存立即釋放。這個原則決定一般情況下,不會有內存泄露的情況存在,但存在特殊情況,也是本章最后一個專題要闡述的問題。

內存泄露是指,一塊沒有被指針引用的內存,但由于一些原因,無法釋放,造成內存浪費的情況。

管理原則

  • 強引用對象指針使用中的內存絕對不會釋放。
  • 歸零弱引用對象指針使用中的內存,釋放情況由其他對象指針決定,本身不影響內存釋放與否,但其指向的內存一旦釋放,本身立即置nil,保證不出現野指針。
  • 弱引用對象指針使用中的內存,釋放情況由其他對象指針決定,本身不影響內存釋放與否,但其指向的內存一旦釋放,本身值不會發生改變,會出現野指針的情況。
  • AUTO類型對象指針使用過或使用中的內存,出釋放池才會釋放。通過AUTO類型與釋放池配合使用,可以精確調節內存時間,提前或延后。

2.對象引用類型

對象引用類型有如下四種

  • 強引用:__strong修飾的對象指針或無修飾的對象指針
  • 歸零弱引用:__weak修飾的對象指針
  • 弱引用:__unsafe__unretain修飾的對象指針
  • AUTO類型:__autoreleasing修飾的對象指針

首先分析強引用對象指針的使用情況。在分析內存釋放情況時,我們需要一個測試類進行釋放測試。當一個對象釋放時,它的dealloc方法會被調用。所以我們在dealloc方法中進行相關輸出,便能精確看到,該對象何時釋放。

@interface Test : NSObject@end @implementation Test - (void)dealloc { NSLog(@"該對象釋放"); } @end

情況1

int main(int argc, const char * argv[]) { { Test * t = [[Test alloc]init]; } //代碼運行至此,t的作用域結束,t指向的內存并無其他對象指針使用,所以,該內存在此釋放。 return 0; }

情況2

int main(int argc, const char * argv[]) { { Test * t1; { Test * t = [[Test alloc]init]; t1 = t; } //代碼運行至此,t作用域結束,但t指向的內存仍有t1對象指針使用,所以在此該內存不會釋放。 } //代碼運行至此,t1作用域結束,t1指向的內存再無其他對象指針使用,所以在此內存釋放。 return 0; }

情況3

int main(int argc, const char * argv[]) { { Test * t = [[Test alloc]init]; t = nil;//代碼運行至此,t不再指向之前分配的內存,之前的內存無對象指針使用,釋放。 } return 0; }

以上是強引用的常用情況,其對象指針并無任何修飾符進行修飾,但已經OC語法規定,對象指針無修飾時,為強引用類型。

我們繼續討論歸零弱引用類型的對象指針對內存的影響。

情況1

int main(int argc, const char * argv[]) { { __weak Test * t1; { Test * t = [[Test alloc]init]; t1 = t; } //代碼運行至此,t作用域結束,t指向的內存仍有t1對象指針使用,但t1為歸零弱引用,不會影響對象釋放情況,所以在此內存釋放,且t1本身值變為nil } return 0; }

情況2

int main(int argc, const char * argv[]) { __weak Test * t1 = [[Test alloc]init];//在此語句運行時,分配的內存并無除弱引用對象指針以外的對象指針使用,所以,該內存立即釋放。 return 0; }

以上是歸零弱引用的情況,不常用。歸零弱引用只有一種情況下使用:

  • 代碼塊回調接口中的自身代碼塊引用自身對象

例如:

@interface Room : NSObject @property (strong, nonatomic) Light *lightA; @property (strong, nonatomic) SwitchB *s; @end @implementation Room - (instancetype)init { self = [super init]; if (self) { self.lightA = [[Light alloc] init]; self.s = [[SwitchB alloc] init]; __weak __block Room * copy_self = self;//打破強引用循環,強引用循環的概念下文會講解。 self.s.changeStateBlockHandle = ^(SwitchState state) { if (state == SwitchStateOff) { [self.lightA turnOff]; } else { [self.lightA turnOn]; } }; } return self; } @end

弱引用和歸零弱引用管理內存的釋放時間相同。弱引用是OC為兼容之前特殊情況下的內存管理而做的一個不常用類型。所以之后,我們不會使用弱引用,所有需要弱引用的地方全部以歸零弱引用代替。

3.屬性引用類型

屬性的內存控制符,有四種情況。

  • strong
  • weak
  • copy
  • assgin

對于對象來說,可選的只有前三種。第四種,assgin為無內存管理,主要針對基礎數據類型設計。例如

@property (assgin, nonatomic) int a;

如果一個屬性是對象,那么其屬性內存控制符必然是前三種之一。

strong:默認情況下使用,除特殊情況。

weak:在遇到強引用循環時,使用。

copy:在進行數值對象賦值時,使用。

例如

@property (copy, nonatomic) NSString * name; @property (copy, nonatomic) NSNumber * age;

但也可以strong代替,所以,copy使用場景也不多見。

4.強引用循環

在內存管理中,強引用循環是最嚴重的失誤,會造成大量內存泄露。通過一個例子來說明為什么會產生泄露。

首先用實際生活中的一個場景來具體的說明一下,問題產生的原因。

例如,現在在一個教室,有學生有老師。老師對自己的要求是,學生不離開教室,我就不離開教室。而學生對自己的要求是,老師不離開教室,我就不離開教室。這樣一直持續下去的結果就是,雙方誰都不會離開教室。

然后我們再看一下代碼中何時會產生這種情況。

@interface Student : NSObject@property (strong, nonatomic) Teacher *tea; @end @interface Teacher : NSObject@property (strong, nonatomic) Student *stu; @end main() {{Teacher * tea = [[Teacher alloc] init];Student * stu = [[Student alloc] init];tea.stu = stu;stu.tea = tea;}}

上述代碼中,可以發現,Student類有一個strong類型的屬性tea,通過管理原則我們可以知道,stu對象存在其強引用屬性tea一定存在,不會釋放。同樣Teacher有一個strong屬性stu,tea對象存在意味著stu對象也絕對不會釋放。這樣當兩個對象指針作用域消失時,其使用的內存無法釋放,出現內存泄露。

這種問題便是內存管理中會遇到的強引用循環,也是目前能夠造成內存泄露的唯一原因。需要對這樣的情況在設計層面進行避免。互相包含對方類型的屬性的結構中,必須有一方為歸零弱引用。

目前存在雙向包含的場景只有在回調中會用到

  • 目標動作回調中,儲存target對象的屬性為weak
  • 委托回調中,儲存delegate委托人的屬性為weak

除上述兩種情況外,其他地方默認使用strong修飾屬性即可。

5.AUTO類型與釋放池

在內存管理中有一種較為特殊的類型叫AUTO類型,雖然名字和自動相關,但其釋放仍需要手動配置釋放池來調整。

__autoreleasing:被此種修飾符修飾的對象指針,其使用過和使用中的內存在出釋放池時才會釋放。所以可以通過手動配置自動釋放池的位置來調節釋放時間。

延遲釋放的例子:

@autoreleasepool {{__autoreleasing Student * stu = [[Student alloc] init];}//在此,stu的作用域雖然已經結束,但stu為AUTO類型,所以等代碼運行到釋放池結束才會釋放 } //在此位置,內存釋放

提前釋放的例子:

__autoreleasing Student * stu; @autoreleasepool {stu = [[Student alloc] init]; } //在此位置,內存釋放,雖然stu的作用域沒有結束

使用AUTO的類型有兩種情況

情況1為對象的便利構造器方法,需要延遲釋放

+(id)student {__autoreleasing Student * stu = [[Student alloc] init]; return stu; }

OC語言規定,方法返回的內存必須為AUTO類型。

情況2為在一個封閉循環內,用便利構造器創建對象

for(int i = 0;i<10000;i++) { @autoreleasepool { __autoreleasing Student * stu = [Student student]; } }

因便利構造器返回的對象為AUTO類型,所以該對象指針使用的內存只有在出釋放池時才會釋放。但for循環中無釋放池,這會造成,大量無用的對象無法立即釋放。

添加釋放池之后,內存便可以在使用結束之后立即釋放。

?

[代碼展示]

?

1.

======Test類的聲明======

#import <Foundation/Foundation.h>

?

@interface Test : NSObject

?

@end

?======Test類的實現======

?

#import "Test.h"

?

@implementation Test

//對象被釋放之前要調用的方法

-(void)dealloc

{

? ? NSLog(@"Test被釋放。");

}

@end

?

?======main======

#import <Foundation/Foundation.h>

#import "Test.h"

int main(int argc, const char * argv[]) {

? ? //__strong 強引用,它會造成對象的引用計數器的變化(+1)

? ? @autoreleasepool {

?? ? ? ?

?? ? ? __strong Test *t2;

? ? ? ? {

? ? ? ? ? ? Test *t = [[Test alloc]init];

? ? ? ? ? ? t2 = t;

? ? ? ? ? ? t=nil;

? ? ? ? ? ? NSLog(@"2");

? ? ? ? }

? ? ? ? NSLog(@"1");

? ? }

? ? NSLog(@"3");

?? ?

? ?

?

? ? return 0;

}

======運行結果======

2

1

Test被釋放。

3

?

2.

======Test類的聲明======

#import <Foundation/Foundation.h>

?

@interface Test : NSObject

?

@end

======Test類的實現======

#import "Test.h"

?

@implementation Test

-(void)dealloc

{

? ? NSLog(@"Test被釋放");

}

@end

======main======

#import <Foundation/Foundation.h>

#import "Test.h"

int main(int argc, const char * argv[]) {

//? ? @autoreleasepool {

//? ? ? ? //__weak 弱引用,不會造成引用計數器的變化,同時也不能阻止對象的釋放,對象被釋放后自動指向了nil

//? ? ? ? __weak Test *t2;

//? ? ? ? {

//? ? ? ? ? ? __strong Test *t = [[Test alloc]init];

//? ? ? ? ? ? t2 = t;

//? ? ? ? ? ? NSLog(@"%p",t2);

//? ? ? ? ? ? NSLog(@"1");

//? ? ? ? }

//? ? ? ? NSLog(@"%p",t2);

//? ? ? ? NSLog(@"2");

//? ? }

?? ?

? ? @autoreleasepool {

? ? ? ? //__unsafe_unretained 與__weak相同,在對象被釋放后不會指向nil

? ? ? ? __unsafe_unretained Test *t2;

? ? ? ? {

? ? ? ? ? ? __strong Test *t = [[Test alloc]init];

? ? ? ? ? ? t2 = t;

? ? ? ? ? ? NSLog(@"%p",t2);

? ? ? ? ? ? NSLog(@"1");

? ? ? ? }

? ? ? ? NSLog(@"%p",t2);

? ? ? ? NSLog(@"2");

? ? }

? ? return 0;

}

======運行結果======

0x100300220

1

Test被釋放

0x100300220

2

?

轉載于:https://www.cnblogs.com/lqios/p/4288271.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的[objective-c] 08 - 内存管理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。