偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

垃圾回收是一個錯誤

開發(fā) 前端
看到?jīng)]?這已經(jīng)不是“我寫了個大對象結(jié)果GC卡了一下”這種程度的問題了,這是蘋果這種量級的公司都壓不住的系統(tǒng)性問題。你要知道,他們干的還是“密碼管理”這種活——高頻、敏感、延遲敏感、請求量巨大的線上服務(wù)。

蘋果最近寫了一篇很輕描淡寫的技術(shù)遷移文:他們把密碼管理服務(wù)從 Java 搬到了 Swift,性能一飛沖天。

寫得很克制,結(jié)果信息量爆炸。

看完只想說一句:原來不是我們寫得不行,是垃圾回收(GC)這條路本身就有坑。

蘋果點破了那個所有人都不想說的真相

文里有一段話反復(fù)看了三遍,給你摘出來:


我們先沒急著換語言,先是把 JVM 能調(diào)的參數(shù)都調(diào)了。 用了 G1 GC,這個 GC 比老一代強很多:能控制暫停時間、有分區(qū)、還能并行干活。 ——但!在高并發(fā)場景下,GC 還是難搞:一來會有長暫停,二來性能開銷會頂上來,三來要想讓它適配各種各樣的業(yè)務(wù),就得一直細(xì)調(diào)、細(xì)調(diào)、再細(xì)調(diào)。

看到?jīng)]?這已經(jīng)不是“我寫了個大對象結(jié)果GC卡了一下”這種程度的問題了,這是蘋果這種量級的公司都壓不住的系統(tǒng)性問題。

你要知道,他們干的還是“密碼管理”這種活——高頻、敏感、延遲敏感、請求量巨大的線上服務(wù)。

“討厭GC”其實很多人想說但不敢說

大家對 GC 的情緒也不算中立的。

在移動端上這一點更明顯: 你認(rèn)真滾動一個 Flutter 界面,動畫正絲滑,GC 突然說:該洗一洗內(nèi)存了——咔!掉幀。

你用戶根本不在乎你在做什么回收算法,只知道:“怎么卡了一下?”

以前總覺得: “行,客戶端容易卡是因為 UI 線程比較嬌貴;但在服務(wù)器上,總有 20ms 的網(wǎng)絡(luò)延遲,GC 卡個十幾毫秒,應(yīng)該沒人能看出來吧?”

——蘋果這篇文直接告訴你:想多了。

它不是“偶然卡一下”的問題,是你量一旦上來了,GC 這套機制本身就變成了阻力。 一個密碼管理服務(wù),全球幾百萬、幾千萬設(shè)備,分分鐘都是對象分配和釋放,GC 的成本就不再是“小數(shù)點后第二位”的事了。

先回憶一下:GC 最原始的樣子有多粗暴

一開始的垃圾回收很樸素:停世界,涂顏色。

  • 程序停一停,誰也別動
  • 從“根”(棧、全局、寄存器)開始,把能走到的對象都標(biāo)成“活的”
  • 其他的都當(dāng)垃圾,一把丟掉

這種叫標(biāo)記-清除,思想簡單,工程實現(xiàn)也比較直觀。 問題也很直觀:你得停。

游戲里就是卡頓,前端里就是掉幀,后端里就是尾延遲躥上去。

于是這一停世界,就讓幾十年的語言設(shè)計師、JVM 工程師、runtime 大神們開始拼命“降卡頓”。

然后我們走上了一條“工程師自我感動”的路

于是就有了各種“聽起來很高級”的GC:

  • 分代回收
  • 并行、并發(fā)回收
  • 分區(qū) / region-based(Java 的 G1 就是這個)
  • 可預(yù)測暫停時間
  • 增量式、分片式、后臺標(biāo)記……

聽上去是不是很厲害?

但蘋果那句話其實已經(jīng)說透了:它們都沒解決根問題,只是把大坑切成了很多小坑。

GC 還是得暫停的,只是從“一次停很久”變成了“停很多次、每次短一點”。 而且更要命的是:你分區(qū)、你分代,其實都是在給 runtime 自己加開銷。在高負(fù)載場景下,這個開銷很快就會浮出來。

所以蘋果最后說:我們還是換語言吧。

你以為蘋果會秒選 Swift?他們也猶豫過

他們自己寫的:我們其實看了好多語言,不是那種“蘋果出品必用 Swift”那種拍腦袋。

最后還是落到了 Swift,核心原因其實就一個:它不用垃圾回收。

Swift 用的是 ARC(Automatic Reference Counting,自動引用計數(shù))。

它不搞“我過一陣子再來看看誰還能活著”這一套, 它搞的是:“你被引用+1,你不被引用-1;你變成0,我立刻干掉你?!?/span>

這個思路有兩個驚人的優(yōu)點:

  1. 釋放是分散的,不是集中的所以不會突然來一刀,整個線程都進去回收
  2. 時機更可預(yù)期引用一旦沒了,馬上釋放,不會拖到幾秒鐘后再清

這,就是為什么在 UI 場景下,ARC 體驗肉眼可見地更順

蘋果現(xiàn)在的說法是:同樣的爽感,在服務(wù)器上也能拿到。

當(dāng)然,ARC 也不是天使

你要是只說“GC 有暫停,ARC 沒暫?!?,那就太不講究了。

ARC 最大的雷,大家都知道:循環(huán)引用。

A 引用 B,B 引用 A,兩個都有人愛,引用計數(shù)永遠不會變成 0, 但其實外面沒人能走到它們了——這就是一坨泄露。

Swift 的做法是: 給你弱引用(weak)、unowned 這種不參與計數(shù)的引用, 你自己在該用的地方用,不該用的地方別用。

也就是說:ARC 不是傻瓜式的。你還是得懂點內(nèi)存生命周期,不然你也能寫出一鍋爛。

不過話說回來,GC 也不是傻瓜式的

你要是一直往一個全局 List 里塞對象、從來不刪,GC 也清不了你。 本質(zhì)上還是:語言幫你減了 80% 的內(nèi)存活,剩下 20% 還是你自己得有腦子。

所以問題就變成了: ?? 為了這 20%,你愿不愿意換來一個“幾乎不掉幀、幾乎不突刺、尾延遲更穩(wěn)”的世界?

蘋果的答案是:愿意。

那么問題來了:既然 ARC、所有權(quán)、arena 這些都在,為什么當(dāng)年我們選了 GC?

這才是本文真正的靈魂拷問。

你看可選方案其實一大堆:

  • 像 Swift 這樣:引用計數(shù) + 弱引用
  • 像 Rust 這樣:所有權(quán) + 借用檢查
  • 像 Ada 那樣:只能指向“更深”的對象,天生不容易環(huán)
  • 像游戲引擎常用的:區(qū)域 / arena 分配,一幀分配完,一幀回收
  • 像 Jai、很多高性能系統(tǒng)用的:一大塊內(nèi)存開出來,用完一刀清
  • 甚至還有引用計數(shù) + 少量GC兜底這種折衷

你看,路線這么多,我們偏偏走了“讓程序自己去猜你要不要內(nèi)存”的那條。

這事你要是放到公司里來,是不是像這樣


甲:我們能不能在寫代碼的時候就標(biāo)一下“我這個對象多久用完”? 乙:不用,我們寫個超級復(fù)雜的系統(tǒng),隔一會就去全內(nèi)存里掃一遍,看有沒有人不要了。 甲:???

如果這是你同事提的方案,你是不是要拍桌子了?

可是現(xiàn)實世界里,我們真的就這么干了,而且還干了30年。

為啥?我也覺得就是營銷贏了

“看,我們這是像 C 一樣快的語言,但你不用自己 free?!?“你再也不用擔(dān)心內(nèi)存泄露了!” “寫業(yè)務(wù)就行,內(nèi)存我們管?!?/span>

很香,對吧。

于是 Java 火了,.NET 火了,很多企業(yè)都投了,連蘋果這種公司都在用它的 JVM。

但代價是什么?

一整代工程師被教育成:不需要顯式表達生命周期。

然后 runtime 就只能跟個猜你心思的戀人一樣,一遍一遍全內(nèi)存掃,想看你到底還愛不愛這個對象。

每一次掃,都是CPU、內(nèi)存、能源的浪費。

我看到一個 HN 的評論,真是一針見血,我給你翻一下


垃圾回收就是“沉沒成本”的典范。我們30年都在往一個壞主意上砸聰明人。 真相其實是:我們不愿意在語言層面、語法層面給足編譯器“對象會活多久”的上下文; 于是就只好搞一個近乎自我感知的系統(tǒng),去猜我們是不是用完了。 它浪費時間、浪費空間、浪費能量。 要是當(dāng)年這些人去做“更聰明的語言”,而不是去搞“更聰明的GC”,我們今天會過得好很多。 GC 就是壞主意。我高興看到我們終于準(zhǔn)備好往前走了。

你看,這個吐槽有多狠。我們不是不會表達生命周期,是我們懶得表達。于是就有了一個“全內(nèi)存 for 一遍”的東西。

這也是為什么你越調(diào) G1,越覺得像是在貼創(chuàng)可貼

G1、ZGC、Shenandoah…… 名字一個比一個酷, 實現(xiàn)一個比一個復(fù)雜, 論文一個比一個厚, ——但本質(zhì)還是:“我還是要掃,只是我盡量別嚇到你?!?/span>

從結(jié)果看,蘋果還是被嚇到了。 Flutter 開發(fā)者也會被嚇到。 高頻客戶端會被嚇到。 高并發(fā)后端也會被嚇到。

說明問題不在于我們調(diào)得還不夠精妙。是我們走的是不該走的那條路。

如果我來設(shè)計語言,我會這么干

作者原文里說了一句我還挺認(rèn)同的思路,大意是:


我會做一個類似 ARC 的系統(tǒng),但我只允許一個“硬”引用指向某個堆對象,這樣循環(huán)引用從語義上就不成立了,基本上就能做到“又快又傻瓜”。

這其實跟 Rust 的“所有權(quán)只能有一個”有點像,只是思路沒那么硬。 核心都是那個意思:別再讓 runtime 替我們猜了,我們自己說。

而且就算你不喜歡這種路線,也不是非GC不可。 你上面看到了,方法一大堆。

所以,GC 是不是錯了?

如果你的目標(biāo)是

  • 開發(fā)體驗第一
  • 要在 2000 年初對比 C++ 看起來“好輕松哦”
  • 要讓一大批企業(yè)開發(fā)者迅速寫業(yè)務(wù)
  • 要讓培訓(xùn)班能一周教完內(nèi)存
  • 要發(fā)個“write once, run anywhere”式的廣告

那 GC 沒錯,它甚至是商業(yè)上最正確的選擇。

但如果你的目標(biāo)是??

  • 幀率不能抖
  • 后端尾延遲不能飄
  • 能源要省
  • 云成本要控
  • 語言要能清晰表達生命周期
  • 工程要能被未來的人維護

那對不起,GC 這條線,確實該被重新審視了。

蘋果這次遷移,其實就是很大聲地說了這一句:“我們在 JVM 上已經(jīng)把能調(diào)的都調(diào)了,但GC本身還是我們的天花板?!?/span>

這句話,才是最有含金量的。

最后一口狠話

你這么想一下就很魔幻:


我們沒有想辦法在語言里好好說“我這個對象什么時候不用了”; 結(jié)果我們寫了一個巨大的、常駐的、會自己醒來的、會遍歷整個進程內(nèi)存的大型循環(huán), 去猜我們到底用不用一個對象。

要是你公司里有人提說: “這事我不知道你什么時候不用,我就隔十秒全庫掃一遍好了?!?你是不是想說:你是不是有???

但我們對 GC 就是這個態(tài)度:

它已經(jīng)投了三十年了,不能說它錯。

能說。 蘋果已經(jīng)說了。

所以,這篇文章才會叫:Garbage Collection Was A Mistake。

不是說“所有帶GC的語言都不能用”——別搞極端。

而是說:我們這幾十年可能繞了個遠路,把問題丟給了runtime,而不是丟給語言設(shè)計。

現(xiàn)在好了,Rust 出來了,Swift ARC 跑起來了,游戲引擎的 arena 模式走得飛快,WebAssembly 的內(nèi)存故事也開始講了,

我們終于有勇氣回頭看一眼:當(dāng)年那個“全內(nèi)存掃一遍”的主意,是不是有點太粗了。

責(zé)任編輯:武曉燕 來源: 大遷世界
相關(guān)推薦

2020-04-09 08:47:38

Java對象線程

2021-01-12 11:44:48

java垃圾回收

2022-01-20 10:34:49

JVM垃圾回收算法

2017-08-04 10:53:30

回收算法JVM垃圾回收器

2021-01-04 10:08:07

垃圾回收Java虛擬機

2022-03-21 11:33:11

JVM垃圾回收器垃圾回收算法

2021-11-05 15:23:20

JVM回收算法

2023-05-31 09:00:00

2020-11-18 10:54:29

垃圾回收器演進

2019-12-02 16:23:03

Python編程語言“垃圾”回收

2024-08-20 16:27:54

2023-08-08 10:29:55

JVM優(yōu)化垃圾回收

2010-12-13 11:14:04

Java垃圾回收算法

2015-12-10 11:11:06

2009-06-25 17:48:24

Java垃圾回收

2021-03-03 08:13:57

模式垃圾回收

2020-07-09 08:26:42

Kubernetes容器開發(fā)

2023-12-19 21:52:51

Go垃圾回收開發(fā)

2010-09-26 13:29:46

JVM垃圾回收

2019-07-22 08:35:32

Java垃圾回收
點贊
收藏

51CTO技術(shù)棧公眾號