應用程序開發中,內存管理是個重要的話題。
簡單而言,語言層面的內存管理基本有三類:python
如C和曾經的C++。c++
char *some_string = malloc(BUFFER_SIZE); // do something free(some_string);
這個簡單的例子裏用完就釋放還好,可是有時候這個some_string被傳來傳去不知道飛哪兒去了,就比較尷尬。
純手動管理的代價是程序員的心智負擔比較重。
即便後來C++程序員們抽象出RAII這樣的實踐規範,必定程度上下降了管理的複雜度,可是相對來講成本仍是略高。
隨着語言的發展,已經不多有語言只依賴手動管理內存了。程序員
這裏的某些機制其實一般就是引用計數。畢竟這是最簡單的內存管理輔助手段。算法
引用計數是計算機編程語言中的一種內存管理技術,是指將資源(能夠是對象、內存或磁盤空間等等)的被引用次數保存起來,當被引用次數變爲零時就將其釋放的過程。
引用計數你們都瞭解,很少說,單純的自動使用引用計數問題在於沒法解決循環引用的問題。不少語言選擇讓程序員付出一點勞動來解決這個問題。
早年,Objc選擇的是退一步,徹底讓程序員來管理引用計數的加減,稱爲MRC,顯然管理成本偏高。後來推出了ARC,提供了更健全的機制,程序員只要標識出對象間的引用關係是強引用仍是弱引用就能夠了,大大下降了程序員的負擔。
雖然走這個路子的語言不算多,但除了Objc以外仍是有好幾個的。
C++的智能指針跟Objc的ARC就比較類似。而Rust的全部權模型本質上也是相似的。編程
經過GC自動管理內存大概是如今的主流了。對程序員來說實在是太溫馨了,開發時幾乎不用考慮內存管理的問題。Java、JavaScript、Python、go等一大票語言都是走的這條路。
GC是基於可達性分析算法的,即,從根節點(全局變量、局部變量等等)出發,遍歷引用到的對象,全部沒遍歷到的對象就能夠釋放了。
固然從原理到實際應用中間差了十萬八千里。樸素的GC會常常形成Stop The World。一旦Stop-the-world發生,除了GC所需的線程外,其餘線程都將中止工做,中斷了的線程直到GC任務結束才繼續它們的任務。
因而不少GC算法被髮明出來用於優化、減小。常見的CMS、G1回收算法都極大地減小了STW的時間,但仍然不能徹底避免。
R大在Java 大內存應用(10G 以上)會不會出現嚴重的停頓?中提到Zing JVM採用的C4算法是能夠徹底避免STW的,不過看起來爲了不STW,C4算法會吃掉更多的內存,程序吞吐量會受到影響。swift
總結一下吧,純手動管理基本上已被淘汰,ARC(暫且把方法二這類都稱爲ARC吧)和GC對比之下,
對開發者,ARC須要程序員付出必定的代價進行管理,GC則基本上徹底解放雙手;
性能上,GC一般會形成STW現象,對響應時間比較敏感的程序,好比高頻交易系統,是很難接受的,而ARC不會對性能形成明顯影響。編程語言
整體性能上,只要不是內存跑得特別滿,ARC的整體代價是高於GC的。其實想一想就知道了,GC只關注兩次回收間的變化,而ARC要對每一次引用的改變進行計數,整體性能上比GC差是很正常的,但因爲ARC的耗時是均勻分佈在運行時間裏的,一般咱們不用很關注。關於這個問題能夠參考這篇論文。性能
另外比較特別的是,Python的默認解釋器CPython中應用了引用計數與垃圾回收相結合的手法,沒有循環引用的對象會被引用計數回收,剩下的交給GC處理,大大下降了GC的壓力。感受頗有意思。優化
在類ARC方案上,C++提供的能力是比較全面的。這可能跟c++經常使用於一些性能比較苛刻的場景有關。
出於性能緣由,使用c++智能指針時有以下指導思想:線程
Rust也有相似的能力。
而python和Objective-C就沒有這麼多講究,全部的引用計數其實都是shared_ptr。Objc在iOS上這麼多年,然後來的swift也傳承了ARC,基本上能夠認爲,移動端應用從小到大都不差這麼一丟丟性能。
以此推論,絕大部分c++應用也徹底不必關注這幾個指針間的差別,操起shared_ptr就是幹。