iOS之記憶體管理(ARC)

来源:https://www.cnblogs.com/lizheng114/archive/2018/03/28/8371138.html
-Advertisement-
Play Games

iOS的記憶體管理,相信大家都不陌生,之前是使用的MRC,由開發人員手動來管理記憶體,後來使用了ARC,來由系統管理記憶體。本文主要講講Autorelease,Core Foundation對象在記憶體管理方面要註意的地方。 Autorelease 提到記憶體管理,就不得不提autorelease,雖然我們平 ...


iOS的記憶體管理,相信大家都不陌生,之前是使用的MRC,由開發人員手動來管理記憶體,後來使用了ARC,來由系統管理記憶體。本文主要講講Autorelease,Core Foundation對象在記憶體管理方面要註意的地方。

Autorelease

提到記憶體管理,就不得不提autorelease,雖然我們平時開發中很少會感知到它的存在。autorelease就是自動釋放的意思,如果變數使用autorelease來修飾,就表明變數的釋放由系統來完成。

autoreleasepool是由runloop在開啟或者喚醒的時候創建的,當runloop進入睡眠或者釋放掉的時候,autoreleasepool會給pool中的所有對象發送release消息。那麼,由此便引申出一個問題,如果runloop不進入睡眠或者不釋放(例如:主線程,或者某些常駐線程),pool裡面的對象也便不會被釋放,他們會堆積在記憶體中,但是系統會做一些優化,如下:

- (NSMutableArray*)createArrayNoAutorelease{
    id arr = [NSMutableArray arrayWithCapacity:3];
    return arr;
}

- (NSMutableArray*)createArrayAutorelease{
    return [NSMutableArray arrayWithCapacity:3];
}

上面的兩個方法都是表明的要返回NSMutableArray這個對象,但是兩種寫法不同,系統做的處理也不相同。

我們先調用第一個方法 createArrayNoAutorelease方法,然後使用xcode的Product->Perform Action->Assemble xxx來看看,生成如下代碼:

Lfunc_begin1:
....前面省略
	bl	_objc_retainAutoreleasedReturnValue
	.loc	2 56 14                 
	str	r0, [sp, #4]
	.loc	2 57 12 is_stmt 1       
	ldr	r0, [sp, #4]
	bl	_objc_retain
	add	r1, sp, #4
	movs	r2, #0
	.loc	2 58 1                  
	str	r0, [sp]                @ 4-byte Spill
	mov	r0, r1
	mov	r1, r2
	bl	_objc_storeStrong
	ldr	r0, [sp]                @ 4-byte Reload
	.loc	2 58 1 is_stmt 0        
	add	sp, #16
Ltmp3:
	pop.w	{r7, lr}
	b.w	_objc_autoreleaseReturnValue
Ltmp4:
Lfunc_end1:

其中 objc_retainAutoreleasedReturnValue和objc_autoreleaseReturnValue主要用於優化程式運行。本來應該將返回的對象註冊到autoreleasepool中,但是有了這兩個函數,就可以不將對象註冊到autoreleasepool中,而是直接傳遞給調用方,這是性能調優的一個舉措。

我們再來看看調用createArrayAutorelease方法,如下:

Lfunc_begin0:
... 省略
	bl	_objc_retainAutoreleasedReturnValue
	add	r1, sp, #4
	movs	r2, #0
	.loc	2 44 8                 
	str	r0, [sp, #4]
	.loc	2 49 1 is_stmt 1        
	mov	r0, r1
	mov	r1, r2
	bl	_objc_storeStrong
	add	sp, #24
	pop	{r7, pc}
Ltmp1:
Lfunc_end0:

現在對象被註冊到了autoreleasepool中。我們可以使用:

po [NSAutoreleasePool showPools]

來看看當前autoreleasepool的狀況,會發現多出了一個對象,如下圖:

(我只截取了一部分)

註意:對於alloc/new/copy/mutableCopy這樣的方法作為返回對象,編譯器會將他們優化為createArrayNoAutorelease相同的情況

關於autoreleasepool的內部結構,實現原理等,可以參看:

http://www.cocoachina.com/ios/20150610/12093.html

Core Foundation

Core Foundation對象是一組由c語言介面,可以跟Foundation框架的OC對象相互轉換。

要搞清楚Core Foundation對象的記憶體管理,就需要搞清楚:__bridge, __bridge_retained, __bridge_transfer; CFRetain(), CFRelease() 這幾個關鍵詞的概念。

CFRetain(), CFRelease() :Core Foundation對象的記憶體管理方式,跟之前MRC時代的retain和release很像。

    {
        CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, "test", kCFStringEncodingUTF8);
        NSLog(@"%@", str);
        CFRelease(str);
    }

註意:這裡要調用CFRelease(str)方法,不然會有記憶體泄漏。

__bridge:只做類型轉換,不修改對象持有者。如下:

    {
        CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, "test", kCFStringEncodingUTF8);
        NSString *obj = (__bridge NSString*)str;
        NSLog(@"%@", obj);
//        CFRelease(str);
    }

對於從CF轉換為OC對象,一定要調用CFRelease(str)方法,不然會有記憶體泄漏,因為只是做了簡單的指針地址變換,str仍然沒有釋放。

來看一個野指針的例子:

    CFMutableArrayRef cfObject = NULL;
    {
        id obj = [[NSMutableArray alloc] init];
        cfObject = (__bridge CFMutableArrayRef)obj;
        CFShow(cfObject);
    }
    CFRelease(cfObject);

因為__bridge不持有obj對象,所以當大括弧結束以後,obj被釋放,cfObject就成為了野指針,在調用CFRelease方法時就會引發程式崩潰。

__bridge_retained:用於將OC對象轉換為CF對象,持有者也發生改變,需要調用CFRelease方法。

__bridge_transfer:將CF對象轉換為OC對象,同時將對象持有權交給ARC,不需要調用CFRelease方法,如下:

    {
        CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, "test", kCFStringEncodingUTF8);
        NSString *obj = (__bridge_transfer NSString*)str;
        NSLog(@"%@", obj);
//        CFRelease(str);
    }

所以在使用CF對象時,要特別註意記憶體問題。

 

參考文章:

https://yq.aliyun.com/articles/58964

https://juejin.im/entry/579bfdfe5bbb500064d18aca


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.1 查看mysql的安裝路徑: [root@bogon ~]# whereis mysql mysql: /usr/bin/mysql /usr/lib/mysql /usr/share/mysql /usr/share/man/man1/mysql.1.gz 1.2 查看mysql的安裝包: ...
  • About SQL*Plus SQL*Plus is the primary command-line interface to your Oracle database. You use SQL*Plus to start up and shut down the database, set da ...
  • 使用BLOB欄位來保存圖片是不是一個好的方法還存在爭議,小圖片除外。更常用的方法是將圖片保存為一個文件,然後只在數據中保存圖片文件的元數據,比如文件的路徑。但是,如果你想把數據文件(初始數據)打包成一個文件放在你的應用中,這倒是一個很好的方法。 SQLite在iOS設備上運行要比在模擬器上運行慢的多 ...
  • 閱讀目錄 介紹 R 文件的內容 介紹 通過 R 文件引用資源 一、R 文件的內容 在 Android Studio 中 R 文件位於 app -> build -> generated -> source -> r -> debug -> 包名 -> R 要註意幾點: R 文件的本質是一個 java ...
  • 微信公眾號:CodeId有什麼建議可以到公眾號里進行留言。 很高興又和大家見面了,最近寫了個小游戲——2048,這個游戲實現起來不是很難,感覺它對自己的邏輯能力起到一個訓練作用,還不錯,所以今天分享給大家。我是通過小程式寫的,源碼已經放到GitHub上了https://github.com/Craz ...
  • RadioButton的圖標大小並沒有相應的佈局參數,本文通過自定義屬性的方式自定義RadioButton,實現控製圖片大小。 ...
  • 一、介紹 最近一直在做有關JavaScriptCore的技術需求,上周發現一個問題,當在JavaScriptCore在垃圾回收時,項目會有一定幾率發生崩潰。崩潰發生時調用堆棧如下: 圖1 調用堆棧 圖1 調用堆棧 先對上圖中兩個比較重要的堆棧過程做個說明: 圖2 生成JSValue 圖2 生成JSV ...
  • 一、position和anchorPoint 1.簡單介紹 CALayer有2個非常重要的屬性:position和anchorPoint @property CGPoint position; 用來設置CALayer在父層中的位置 以父層的左上角為原點(0, 0) @property CGPoint ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...