ios和android的內存回收機制孰優孰劣?


從來沒掛過人,今天掛一個,居然還是認證賬號?!

當內存不足時,內存回收機制就開始起作用了

實際上,作為Android的開發語言Java沒有提供任何操作來釋放內存(這也是與iOS很大的不同點),是通過系統的內存回收機制來進行管理。Android使用了一個名為Low Memory Killer(LMK)的機制來管理內存,當內存出現不足時,LMK就開始揮舞屠刀殺掉一些。

而ios的 Objective-C

Objective-C的內存回收方式是引用計數的內存回收方式。凡是繼承NSObject的類生成的對象,當對象的計數為0,會對對象執行dealloc並回收。引用計數有個缺點,無法解開循環引用。設想對象A引用B, B引用A,兩個對象計數都不為零,結果無法回收A和B,於是內存泄漏掉了。

作者:奇兔刷機
鏈接:https://www.zhihu.com/question/26616849/answer/180550633
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

此人說 Android 和IOS雙標得這麼離譜,稍微懂點的都能看出來這貨純屬胡扯,你以認證賬號的身份發出來,知乎就不管管嗎?!這還能有70個贊?!

內存管理分為兩個部分,一個是系統級的內存管理,這種管理方式是以進程為單位的;另外一種是語言提供的(Java實際上是JVM去做這件事),這種管理方式是以對象為單位的,您說 Android 的時候說系統級內存管理,講到 IOS 就偷摸轉到語言提供的內存管理了?Java 的 GC 機制被你吃了?我雖然沒做過 IOS 開發,但是我至少知道回收進程和回收對象完全不是一碼事,你這麼誤導人,這個小編是不是該(此處省略不友善內容一萬字)了?


當我的手機有3g內存,我會很享受android的內存機制,當我只有512內存,我絕對會選擇iOS的內存機制。

當我只有1g內存,我都不喜歡,android的卡頓會令我拙計,iOS的safari重新載入令我不爽。


這個應該是個java和objC的比較。

Java里內存的回收是由JVM虛擬機控制的,啥時候回收由JVM決定。這樣做程序員基本上不需要關心內存的泄漏(注意我用的是「基本」)和非法訪問了。回收的過程就是GC,GC會暫停整個程序的運行,深入內存分配樹去尋找垃圾,然後釋放掉。正是由於這棵樹的存在,循環引用不再是個問題。稍後會說循環引用。

objC採用引用計數來管理內存。一個對象引用一次+1,解引用-1,當計數降為0就立即釋放內存。其實這也不是objc的專利了,這是一種很普遍的模式吧。

引用計數有個缺點,無法解開循環引用。設想對象A引用B, B引用A,兩個對象計數都不為零,結果無法回收A和B,於是內存泄漏掉了。

Java用樹描繪了對象間的引用關係。GC的任務就是把圖中沒有任何引用的對象B們找出來,刪掉。什麼演算法?似乎跟不同的實現有關,我也沒深入研究。

在樹的結構下,如果A和B發生了循環引用,那麼無所謂,反正他們與樹沒有關係,GC的時候他們一起被釋放掉。其實所有引用關係最終都能成為「樹」,但是側重點不一樣,JVM依賴樹的結構來尋找垃圾,而objC則只關心引用計數,「樹」只是個附產品。(順便插一局,在Java中,所有的static變數都是根,如果你不小心跟靜態變數發生強引用關係,那麼你就等著內存泄漏吧,所以文章開頭說「基本」)

在objC引用計數下,可以使用弱引用來打破一方對另一方的「強」引用,於是只有A對B或者B對A的引用,反過來是沒有的(在弱引用的時候總是檢查指針是否為空,才能訪問)。這個就不詳說了。

說這麼多,就是想給下面結論做個鋪墊:

JVM:

優點

程序猿不需要太關心這種循環引用導致的內存泄露,減輕了負擔(否則循環引用很容易就寫出來了)

缺點

1. 很難控制內存的釋放時機,大的內存分配往往需要等待GC才能進行

2. GC就是個猛獸,所有線程都要暫停以便GC。有時GC甚至有幾十毫秒——足以讓UI(特別是動畫)卡出翔,這也是Android卡頓的原因之一

objC/引用計數:

優點

內存釋放及時、平滑,時機可控

缺點:

不小心就寫出內存泄漏,要時刻保持清晰的對象間聯繫

Google在Android上確實對虛擬機有所優化(如不同深度的GC),新的ART也降低了每次GC的時間,一些額外的優化也可以避免GC的頻繁發生(如復用對象)。但是這一切的一切都是建立在一個不合適的機制上,你再怎麼優化還是骨子裡殘廢啊,而且回到這種設計的初衷——為了減輕開發負擔(求證?),卻最後增加了後期優化的負擔,優化到最後面對那個跳不過去的龐然大物,只能望J興嘆了。所以我的最終結論是,對於初學者來說,Java確實容易到爆,寫爛代碼也不容易出事兒,然而對於有經驗的開發者來說,前期的小小努力便能換來流暢的App,我更願意選擇iOS。

PS:本人苦逼Android開發者

================= 11月23日 ====================

補充一下:我很樂於看見Google為減少gc帶來的影響這個方向(比如新的ART虛擬機)努力,誰不想方便和快速兩全呢?只是工作中要為無數舊版本的安卓開發,它們真真兒就成了實實在在的硬傷。只能拭目以待,以後要是演算法、硬體都能完全抹去這個帶來的影響,到時候我就投Android一票了。


分為兩個層面:語言和系統。

語言

語言其實沒什麼可多說的,iOS 主要使用 Objective-C 和 Swift,兩者均採用引用計數內存管理機制,當堆內存對象不再需要使用時就會立刻釋放(retainCount = 0),macOS 早期也存在 GC,現在已經廢除;而 Android 主要開發語言是 Java,很典型的用 GC 來進行內存管理,在內存資源 critical 時才會進行垃圾對象的回收。

語言層面的優劣我覺得影響不大,採用引用計數能帶來更好的性能,但也會增加一定創造 bug 的幾率(我是說循環引用);而 Java 因為有 GC 其實如果你不操心內存問題,你的 app 也不會出現問題,但是為了更好的效率,你可能需要做的優化要更多,因為頻繁 GC 是會嚴重影響 app 流暢度的(GC 時所有線程暫停)。

系統

系統從觀感上兩者差異較大,但是 iOS 不開源,並且這方面從文檔上我看得比較少,所以著重說一下 Android。Android 可以說完全不限制後台的活動,這裡說的不限制也不是完全不限制,後面我會提到。iOS app 當進入後台後,僅有幾分鐘的活躍時間,之後進程就被 suspend 了,不再有任何 CPU 時間。而 Android,如果你願意,你可以一直在後台佔用 CPU,當然,前提是你不能 drain the memory。

Android 有一個很完善的分級內存管理制度,詳細的分級可以參考 ComponentCallbacks2 介面中的定義:

ComponentCallbacks2 | Android Developers 進程和線程 | Android Developers

系統在內存緊缺時會對所有的進程進行審計,後台不可見進程肯定會被優先宰掉,前台進程也不是不會被殺,只是被殺的優先順序最低,總之 Android 也是有自己的一套進程淘汰機制,但相較於 iOS 顯得比較寬鬆。所以經常能夠看到,內存相同時,iOS 總傾向於先釋放一些資源,而 Android 則傾向於等內存快用完了再說。但是 Android 本身由於各種原因,app 的內存佔用率本來就很高,所以 Android 在低內存的情況下也有很嚴重的不斷釋放資源的問題,這也造成了設備卡頓。

iOS 和 Android 的內存回收機制各有各的好處,Android 可以最大限度地利用設備的資源,可以同時做更多的事情;iOS 則可以長期保持一個很流暢的體驗,不過要忍受的就是各種重新載入。


很久沒做Android開發了,不知道Android是否支持到java最新的G1垃圾回收器。先大概講講Java的內存回收機制。

內存回收其實分三個問題:1,什麼對象該被回收。2,什麼時候回收。3,怎麼回收我看到很多答案都只回答了第一個問題,但實際過程中第二,三個問題才是真正影響性能的。

1:什麼對象該被回收。Java即支持計數方式(有引用計數+1,斷開-1,計數為0則標記為可清除),也支持根節點做最短路徑的遍歷。不跟根節點相連的對象標記為可刪除(解決循環引用問題)

2:什麼時候回收?被標記為可刪除的對象,並不是立刻刪除的。必須等到Java需要執行gc的時刻。通常gc發生在內存不足的時候,但有的時候內存碎片過多也會引發gc。但gc操作非常影響性能,有的對象操作頻繁(比如臨時變數),有的對象又需要常駐內存,所以Java把對象劃分各個區域。老年代,年輕代等等。年輕代都是新對象,操作頻繁,所以做gc影響小。老年代一般都是大對象,需要常駐內存,減少gc的次數。這樣減少了內存碎片的影響,只有到整體內存都不足的時候才會執行全局gc。

3:怎麼gc。gc不僅僅是把對象從內存中擦除,還需要對內存整理。否則會產生大量內存碎片。通常做法有這幾種:先清內存,再整理;內存區域分成2部分。只在一個區域做操作,gc的時候把存活對象複製到另一個區域。(還有幾種記不清了)。如2中所說,不同區域根據自身特點,選擇不同的gc方法。

手機打字,全靠記憶,有錯指出。

iOS了解不多,不過應該也是要走這三個步驟。不過java內存回收經歷了很多年的演變,iOS的複雜度應該不及Java。確切的說,手機平台也不需要這麼複雜的gc機制。所以谷歌一直在對Android做精簡,優化。而iOS本身就是針對手機平台設計的,它可能沒安卓gc強大但更適合手機。想想當年塞班,一個int變數分2個位元組,4個位元組,8個位元組等幾個版本,每一寸內存都要計算清楚才能使用。這樣塞班才做到了低硬體下的高效運行。Java提升了安卓開發效率,也帶來了過重的JVM從而導致硬體競賽。


我只知道用iPhone的網頁瀏覽器刷知乎是一件極為痛苦的事情,每次後退的重載,媽的,忍不住爆粗口,因為我現在就要回退了,F**k!


iOS的內存機制應該分為兩種MRC和ARC,怎麼不見有人回答?


3GB內存的手機只有81MB的可用內存了,如果此時打開需要256MB內存的「騰訊視頻」,會提示「內存不足」嗎?答案是不會的。

當內存不足時,內存回收機制就開始起作用了

實際上,作為Android的開發語言Java沒有提供任何操作來釋放內存(這也是與iOS很大的不同點),是通過系統的內存回收機制來進行管理。Android使用了一個名為Low Memory Killer(LMK)的機制來管理內存,當內存出現不足時,LMK就開始揮舞屠刀殺掉一些。

而ios的 Objective-C

Objective-C的內存回收方式是引用計數的內存回收方式。凡是繼承NSObject的類生成的對象,當對象的計數為0,會對對象執行dealloc並回收。引用計數有個缺點,無法解開循環引用。設想對象A引用B, B引用A,兩個對象計數都不為零,結果無法回收A和B,於是內存泄漏掉了。

所以 Android內存回收機制是優於IOS的。


c好 ,但是大型業務系統 你想寫多久? c++好 但是系統大了 要維護簡直就是摸屎。java好,但是,蹩腳的泛型,臃腫的機制都不太好用。js python 等腳本語言好,但是那運行效率相比前幾種都差非常多,開發效率倒是高了一些,但還是建立在高級封裝的情況下。

那什麼語言好呢?答案是都好,每種語言適合不同的場景。類c的彙編的 屬於底層絕對 不會被替代,越來越龐大的業務需求使java等規範性強的語言更有集體開發優勢。輕量的業務 快速的迭代 使得動態語言更有優勢。


蘋果的好點吧,看看阿里巴巴眾軟體在不同平台的德行,就能窺見一斑


Java原來就是使用引用計數的,後來拋棄了這個方案換成現在的,你竟然說比iOS的垃圾...我是一個iOS的開發者,引用計數你要知道他的具體實現是使用一個referenceMap來記錄所有對象的引用計數,用內存地址為key,引用計數為value,內存中存在多少個對象,這裡面就有多小個item,實際上比現在安卓使用的方法所佔用的內存要大的,不夠內存的時候,引用計數的方案只會更慘,而且增加了開發者代碼上的負擔,內存足夠的時候大家都很好,GC帶來的卡頓現在的安卓機哪裡還有


居然沒人解釋

蘋果為啥不用GC機制是為何?

內存較小的安卓越用越卡而相同內存大小的iOS(系統更新除外)基本不會到底是何原因?

此處省略解釋一萬行

(雙十一單身貴族偷懶不做搬運工)

至少在我看來以上兩點證明了iOS的內存回收機制在性能表現上更優。

另外,iOS回收機制的典型問題就是會殺進程,後台運行會限制內存使用,這對於大部分開發者來說是不太樂意的,對於愛玩機的人來說也是一大劣勢。


推薦閱讀:

原生 Android 的使用體驗是什麼樣的?
有哪些值得推薦的 Android 應用?
說 OPPO、vivo 不好的人,用過他們的產品嗎?
蘋果耳機的線控是什麼結構?為什麼安卓的手機不能正常使用?請問可以通過什麼方式解決嗎(比如軟體之類的)?
應該現在買華為MT10Pro 還是等明年買三星S9+?

TAG:Android應用 | Android開發 | Android手機 | Android刷機 | Android |