首頁歷史 > 正文

Java要拋棄祖宗的基業,Java程式設計師危險了?

2022-09-22由 碼農翻身 發表于 歷史

第11代Java國王坐在寶座上,俯視著臣民。

經過歷代國王的勵精圖治,他的Java帝國正處於巔峰狀態。

一群大臣看到新王登基,馬上上來拍馬屁。

“從後端到手機端,從手機端到大資料,帝國疆域無邊無際。” 執行緒大臣率先定了基調。

“Java是企業級應用無可撼動的霸主,生態環境極大豐富。Spring已經統治了後端開發。” 年邁的JVM大臣居然誇起Spring來!

“Java虛擬機器效能強大,其他語言虛擬機器都是玩具。” Spring大臣趕緊投桃報李。

……

都是一些聽過幾百遍的、老掉牙的東西。

國王聽得有些煩,揮手讓眾人退下。

他決定帶幾個保鏢,微服出宮,到外邊親自走一走,看一看。

微服私訪

走出都城大門,國王看到了一望無際的程式碼田地。

烈日下,無數的Java碼農在這裡辛苦勞作,CRUD的勞動號子響徹雲霄。

國王走近一看,果然,碼農們用的工具都是SpringBoot和Spring Cloud,看來大臣所言不虛。

前面的大樹下,一箇中年人開著小茶鋪,幾個碼農聚在那裡,一邊休息喝水、一邊乘涼聊天。

Java要拋棄祖宗的基業,Java程式設計師危險了?

國王悄悄走近。

中年人打著蒲扇,笑眯眯地說:諸位,你們知不知道,

Java已經大禍臨頭,你們有可能要失業了

一個戴著厚厚眼鏡的碼農笑得把茶都噴了出來:哈哈哈,危言聳聽,這怎麼可能?

中年人慢悠悠地說:時代變了,

原來的Java特別適合大規模的伺服器端應用,尤其擅長時間高效能執行

。現在是雲計算時代,微服務時代,有了容器,叢集,服務可以隨時重啟,並且微服務越來越小,用什麼語言都可以。

Java要拋棄祖宗的基業,Java程式設計師危險了?

另一個花格子襯衫碼農說:那也可以用Java寫啊,SpringBoot挺好的啊,約定重於配置,內建伺服器,一個jar包就跑起來。

其餘幾個碼農紛紛附和,國王也暗自點頭。

中年人笑道:雲端應用要求

1。 映象小 2。 啟動速度快,即起即用

。Java能做到嗎?

厚眼鏡碼農說:嗯,

Java的docker映象動輒上G, 冷啟動實在太慢了,每次都得等半天

花格子襯衫說:還有

Spring啟動時用了太多的反射黑魔法,啟動速度更慢

中年人說道:這就對了,我帶著小茶鋪遊歷過Python王國、JavaScript王國,Go王國,人家那裡就沒有這樣的問題,非常適合雲端應用,你們不妨去看看啊。

一番話說得這幾個Java碼農動了心,開始竊竊私語,打探去那些王國的道路。

國王意識到這個中年人來者不善,給保鏢使了個顏色。

保鏢掀翻小茶鋪,扭起中年人就走,留下幾個碼農目瞪口呆。

三個計策

國王召來Spring大臣和JVM大臣,一起審問這個中年人。

國王:你是何人,為什麼在那裡危言聳聽、鼓惑我朝年輕人?

中年人:小民說的都是事實啊,陛下,您可能被矇蔽了,外界正在發生翻天覆地的變化啊,Java如果不與時俱進,岌岌可危啊。

Spring大臣和JVM大臣互相看了一眼,意味深長。

國王倒不在意,問道:你有什麼建議?

中年人:小民有一個上策、中策和下策,陛下想先聽哪一個?

國王:哦?三個計策?先說說下策。

中年人:下策自然是保留現狀不變。

Spring大臣:相當於沒說,中策呢?

中年人:中策就是改Spring,Spring應用在啟動時會掃描程式碼中的bean,然後用反射的方式註冊bean,這種做法的耗時與應用的程式碼量成正比,所以啟動效能會很差。

如果在編譯時把反射轉化為直接呼叫的類,將會大幅提升應用的啟動速度

。我的研究顯示,這種辦法至少可以將成本降低50%,並且民間已經出現了一個叫做Micronaut的框架,它已經實現了

編譯期的依賴注入

Java要拋棄祖宗的基業,Java程式設計師危險了?

Spring大臣一聽這傢伙要把自己幹掉,大驚失色,趕緊跪倒。

他先回顧了祖上如何用SpringMVC乾死Struts的英勇事蹟,又不動聲色地提起自己如何與時俱進,用SpringBoot、Spring Cloud,Spring WebFlux在微服務時代和反應式程式設計時代勇立潮頭。希望Java國王能念起舊情。

國王眼珠一轉,看了一眼JVM大臣:好吧,也許這種辦法能提升Spring應用的啟動速度,但是據我所知

JVM的啟動速度也很慢

,這又該怎麼辦?

中年人:這就是我要說的上策了,

拋棄JVM,把Java程式編譯成原生代碼來執行!

Java要拋棄祖宗的基業,Java程式設計師危險了?

“大膽!你這是要革命,要謀反!” JVM大臣忍不住了。

“陛下,這等狂悖之徒,拉下去問斬吧!” Spring大臣也立刻拱火。

國王心裡很清楚,二十多年了,Java帝國最厲害的無過於位元組碼和JVM,如今ZGC垃圾回收器停頓時間不超過10ms,停頓時間還不會隨著堆的增大而增大,JVM的JIT也爐火純青,在執行時找到最熱點的程式碼,編譯成本地二進位制執行,效率直逼C語言!

相比之下,JavaScript和Python虛擬機器能叫虛擬機器嗎?玩具而已!它們怎麼不強調自己的停頓時長?

不過這個計策倒是非常大膽,雲計算時代,真的需要JVM嗎?

國王陷入沉思。

拋棄JVM

JVM大臣看到國王不說話,又描述了一遍Java程式的生命週期。

1。JVM初始化

2。 應用初始化

3。應用預熱

4。應用穩定

5。關閉

Java要拋棄祖宗的基業,Java程式設計師危險了?

每個階段都有著重要使命,尤其是應用預熱的時候,會把Java位元組碼編譯成原生代碼。

“如果拋棄JVM,前輩們所做的所有努力都不復存在!這會動搖我Java帝國的國本啊!” JVM大臣伏地乾嚎。

Java程式監控、擴充套件、jstat、jstack、jmap都用不了了。

除錯的時候,也只能用複雜的GDB彙編除錯,非常麻煩。

但是編譯成原生代碼,好處也非常明顯,沒有冷啟動問題,啟動即巔峰。

看到國王依然沒有反應,JVM大臣決定丟擲殺手鐧:

“陛下,

我Java帝國之所以能稱雄世界,關鍵就是生態極其豐富,框架和類庫覆蓋了後端開發的所有方面。

“而這些

框架和類庫中在大量地使用反射,甚至用動態代理在執行時動態生成位元組碼

,換句話這些東西在編譯時根本無法確定,只有到執行時才能確定。”

“舉個例子,對於Class。forName(“x。y。z”)這樣的程式碼,如何編譯時就把它變成成原生代碼?”

姜果然是老的辣,JVM大臣一下子就抓住了最關鍵的點,把皮球踢給了中年人。

沒想到中年人胸有成竹:“這非常簡單,在做靜態程式碼分析的時候我會發現x。y。z是個需要被裝載的類,然後把它也編譯成原生代碼!”

“那如果這裡不是個字串的值,而是一個變數呢?Class。forName(

someClassName

)” JVM老頭得意地笑,他早就挖好了坑。

“那就沒辦法了,只好讓使用者在配置檔案中告訴我們哪些類需要編譯成原生代碼了。”

“哈哈哈,說得輕巧,一個框架用了那麼多反射,你讓使用者在配置檔案中全部提前告訴你,怎麼可能?”

中年人不甘示弱:“那我可以開發一個程式,讓使用者的程式執行一遍,我的程式監控使用者的程式哪些地方用了反射,然後自動生成配置檔案!”

“程式那麼多分支,你執行一遍就能找到所有用到反射的地方?”

JVM大臣轉向國王,斬釘截鐵地說:“陛下,此法斷不可行。”

“寡人覺得這其實就是不滿足

封閉性原則

。除了反射之外,還有動態代理,JNI,序列化等,當Java程式碼使用這些特性的時候,靜態編譯就會遇到問題,需要想變通辦法,而變通辦法又無法覆蓋所有情況。”

國王果然是國王,高屋建瓴。

“陛下真是英明,一下子就上升到了理論層面,我等望塵莫及。” JVM趕緊拍馬屁。

編譯

“陛下,把這個散播謠言,鼓惑人心的傢伙拉下去宰了吧!” Spring大臣提醒道。

“雖然Java的動態性無法完美滿足封閉性原則,但是靜態編譯確實是非常誘人,你說說,具體怎麼做。” 國王不理Spring大臣,繼續詢問中年人。

“這個嘛,小民有個基本的思路,就是由

使用者指定程式入口,嗯,相當於main函式,然後靜態編譯器從這裡開始分析程式的可達範圍,把所有的可達的函式和一個小的執行時支援程式碼編譯成native image。

“可笑啊可笑,你難道忘記了Java是個面向物件的語言,多型無處不在?” JVM大臣諷刺。

“我給你舉個例子,看看你怎麼做靜態分析。”

void process(List employees){ int size = employees。size(); ……}

“這個List是JDK的一個介面,JDK有很多實現類(ArrayList,LinkedList,Vector等),我們的專案也有很多自定義的List實現類,employees的實際型別只能在執行時確定,你的靜態分析如何確定呢?”

Java要拋棄祖宗的基業,Java程式設計師危險了?

“你不會把List的所有實現類都給編譯成二進位制程式碼吧?” Spring大臣馬上添油加醋。

“如果是這樣的函式

void process(Object o)

,Object是所有型別的根,難道你要編譯所有的類?哈哈哈!” JVM大臣不由得大笑起來。

“那肯定不行,我有個獨門絕技,叫‘

指向性分析

’,可以在不執行程式的情況下,找到一個型別變數在執行時的可能型別。” 中年人不慌不忙。

指向性分析?Spring大臣和JVM大臣再次對視,他們明白這位中年人不會多說了。

國王盯著這位中年人,問道:“你叫什麼名字?”

“小民叫Graal。”

國王心裡盤算起來。

雲計算時代,容器技術的出現,write once, run anywhere已經不重要了。

相反,Java確實面臨著映象大,冷啟動慢的嚴峻挑戰。

把Java程式碼編譯成原生代碼,要拋棄祖宗的基業,但可能是破局的關鍵。

自己作為新一代國王,堅決不能吃老本,更不能成為亡國之君,所有可能的方向都要嘗試。

想到此處,國王對中年人說:“好吧Graal,寡人已經明白你的意圖,現在給你一隊人馬,專門研究靜態編譯技術!Spring大臣你要密切配合!”

尾聲

幾個月後,中年人推出了一個新的虛擬機器,叫做GraalVM,這個VM野心極大,不僅實現了把Java編譯成原生代碼,還支援JavaScript, Ruby, R,Python等語言。

Java要拋棄祖宗的基業,Java程式設計師危險了?

雖然Spring大臣不太情願,但是國王的聖旨不可違抗,他再次與時俱進,配合GraalVM推出了SpringNative ,把Spring應用編譯成了原生映象。

Java要拋棄祖宗的基業,Java程式設計師危險了?

SpringNative啟動時間提升了50倍,並且啟動即巔峰,記憶體佔用減少了5倍。

Java要拋棄祖宗的基業,Java程式設計師危險了?

Java在雲計算時代的危機暫時度過,未來它還會遇到什麼挑戰呢?

頂部