Erlang与java的内存架构比较
http://blog.sina.com.cn/s/blog_541086000100qod1.html
?我讀了一篇非常非常有趣的文章(Jesper Wilhelmsson的一篇論文),是關(guān)于Erlang 虛擬機(jī)(Erlang VM)內(nèi)存管理策略的。我相信對(duì)比一下Erlang和java的虛擬機(jī)內(nèi)存管理策略,一定很有意思。
???????先給從來(lái)沒(méi)有聽(tīng)說(shuō)過(guò)Erlang的同學(xué)做個(gè)簡(jiǎn)短的介紹。Erlang 是一門(mén)函數(shù)語(yǔ)言,通過(guò)異步消息傳遞(asynchronous message passing)來(lái)處理并發(fā),使用語(yǔ)義拷貝(copy semantics)傳遞消息。即使Erlang分布在多個(gè)虛擬機(jī)上,運(yùn)行在多臺(tái)機(jī)器上,對(duì)程序員來(lái)說(shuō)也是透明的。
???????在某種意義上Erlang和java是相似的,他們都通過(guò)虛擬機(jī)來(lái)獲得可移植性,都采用獨(dú)立于操作系統(tǒng)的字節(jié)碼技術(shù),都使用垃圾回收機(jī)制來(lái)解脫程序員自己管理內(nèi)存的麻煩。
???????Erlang中線程的開(kāi)銷(xiāo)是非常低的。我相信在Erlang中,一個(gè)線程只需要大約512字節(jié)的內(nèi)存。而java線程則需要512K字節(jié)的內(nèi)存,大約是Erlang的一千倍多。對(duì)程序員來(lái)說(shuō),這意味著創(chuàng)建一個(gè)線程非常輕便。典型的Erlang系統(tǒng)中可以有上萬(wàn)的線程。所以Erlang不需要做線程池、executors等等,那些我們寫(xiě)java多線程要用到的東西。
???????在我過(guò)去很少涉獵的語(yǔ)言中,我發(fā)現(xiàn)Erlang既保持了函數(shù)語(yǔ)言的特性,又能夠做出真正的應(yīng)用來(lái)。Erlang健壯的分布式錯(cuò)誤處理非常驚艷,讓編寫(xiě)任何一種網(wǎng)絡(luò)服務(wù)變得相當(dāng)容易。這種狀態(tài)機(jī)的處理方式使web 服務(wù)在出錯(cuò)時(shí),處理回滾非常自然。
???????不過(guò)這篇文章不打算討論Erlang的編程模型,這里主要想討論Erlang虛擬機(jī)的內(nèi)存管理方式。
???????目前java虛擬機(jī)采用了一種被Erlang程序員稱作“共享堆”的機(jī)制,虛擬機(jī)維護(hù)了一個(gè)可以被所有線程共享和使用的大堆(堆和棧什么區(qū)別)。這個(gè)堆占用了虛擬機(jī)的大部分內(nèi)存。在這個(gè)大堆里,也包括了虛擬機(jī)的一些特殊數(shù)據(jù)區(qū)域,例如代碼緩存和永久區(qū)。這些特殊數(shù)據(jù)區(qū)也是被所有線程共享的。
???????相反的,Erlang使用一種私有堆的技術(shù)。每個(gè)線程都有一個(gè)只屬于自己的小堆,里面包含了這個(gè)線程用到的所有數(shù)據(jù)以及線程棧。這個(gè)堆是在線程被創(chuàng)建的時(shí)候分配的。當(dāng)這個(gè)線程結(jié)束了,它的私有堆內(nèi)存就被虛擬機(jī)收回了。
???????除了私有堆,Erlang中所有的線程都能訪問(wèn)兩個(gè)特殊的堆,二進(jìn)制堆和消息堆。二進(jìn)制堆被分配了大量的數(shù)據(jù)塊,以便線程線間共享數(shù)據(jù)。例如文件輸入或是網(wǎng)絡(luò)緩沖區(qū)。
???????消息堆里放的是消息(messages)數(shù)據(jù)。這些消息也可以在進(jìn)程間共享。線程之間傳遞消息的方式,是從發(fā)送線程復(fù)制一個(gè)指針到接收線程。這些消息數(shù)據(jù)就被存放在消息堆里。
???????我對(duì)Erlang的內(nèi)存模型印象深刻。被它比java更具擴(kuò)展性的內(nèi)存模型給震撼了。而且這門(mén)語(yǔ)言的語(yǔ)法和他的內(nèi)存模型結(jié)合的非常漂亮。
???????因?yàn)橛兴接卸?#xff0c;Erlang線程對(duì)自己的數(shù)據(jù)檢查不需要采用任何形式的鎖。并且私有堆也避免了破壞性的寫(xiě),這樣也就沒(méi)有了對(duì)共享數(shù)據(jù)加鎖的需求。
????????最新版的Erlang又往前走了一步,采用了多個(gè)調(diào)度器(scheduler)。每個(gè)物理處理器有一個(gè)調(diào)度器可以保證更精確。而且這也消除了另一種需要檢查的鎖。僅當(dāng)一個(gè)調(diào)度器無(wú)用了,才會(huì)用到鎖,以便從其他處理器上獲得一個(gè)新的調(diào)度器。
???????關(guān)于java,我們?nèi)匀挥泻芏鄸|西要去學(xué)習(xí)。也是就說(shuō),java里還是有些好東西的,也正是因?yàn)檫@點(diǎn),我才沒(méi)有使用大型的Erlang系統(tǒng)。
???????當(dāng)Erlang線程積累了大量數(shù)據(jù)的時(shí)候,Erlang虛擬機(jī)會(huì)重新分配空間,擴(kuò)大私有堆。然而,這個(gè)重新分配的算法會(huì)導(dǎo)致堆空間急速增長(zhǎng)。在高負(fù)載下,我們看到Erlang虛擬機(jī)在幾分鐘內(nèi)吃掉了16G的內(nèi)存!每次發(fā)布版本都要小心的做負(fù)載測(cè)試,看看它的內(nèi)存需求是否能被滿足。
???????Erlang虛擬機(jī)沒(méi)有抑制內(nèi)存增長(zhǎng)的機(jī)制。虛擬機(jī)不斷的分配內(nèi)存,迫使系統(tǒng)不得不使用交換區(qū)(swap),直到虛擬內(nèi)存被耗盡。這可能會(huì)導(dǎo)致用KVM控制臺(tái)訪問(wèn)系統(tǒng)變得很遲鈍。使我們不得不重啟系統(tǒng),才能夠再次訪問(wèn)它。
???????基于隊(duì)列的編程模型讓Erlang編程變得非常愉快,但這也是Elang系統(tǒng)設(shè)計(jì)上的致命缺陷。Erlang的每一個(gè)隊(duì)列都是無(wú)界的。虛擬機(jī)不會(huì)拋出異常,也不會(huì)限制一個(gè)隊(duì)列的消息數(shù)量。有時(shí)候會(huì)出現(xiàn),一個(gè)進(jìn)程可能由于bug而停止工作,或者進(jìn)程消費(fèi)消息的速度跟不上消息發(fā)送速度的情況。在這種情況下,Erlang還是允許這個(gè)進(jìn)程的消息隊(duì)列不斷的增長(zhǎng),直到虛擬機(jī)被殺掉,或是這個(gè)機(jī)器被鎖死了。
???????這意味著當(dāng)你在生產(chǎn)環(huán)境運(yùn)行Erlang虛擬機(jī)時(shí),要配備一個(gè)系統(tǒng)級(jí)的檢測(cè),以便在Erlang內(nèi)存使用量飛漲的時(shí)候能夠殺死進(jìn)程。所以,運(yùn)行大型Erlang應(yīng)用的機(jī)器需要能被遠(yuǎn)程訪問(wèn)和操作(是不是意味著需要經(jīng)常上去處理問(wèn)題??)。
???????總的來(lái)說(shuō),我認(rèn)為在Erlang的工具箱里,“私有堆”是一個(gè)非常強(qiáng)大的工具。它避免了實(shí)時(shí)系統(tǒng)里的鎖機(jī)制,這個(gè)意味著它將比java更具擴(kuò)展性。而java的硬性限制內(nèi)存的模型,則能在你的系統(tǒng)壓力劇增,或是遭受DDOS攻擊的時(shí)候保持穩(wěn)定。
???????有一個(gè)命令行,可以將Erlang的虛擬模型從“私有堆”改成“共享堆”。
???????我喜歡Erlang和java。但他們很難進(jìn)行比較,因?yàn)閷?duì)開(kāi)發(fā)者來(lái)說(shuō),他們的共同點(diǎn)很少。一般情況下,我在大多數(shù)系統(tǒng)里使用java。因?yàn)樗泻芎玫墓ぞ咧С?#xff0c;而且有大量的lib包可以使用。當(dāng)我需要一個(gè)面向信息流的系統(tǒng)時(shí),我會(huì)使用Erlang。這才是Erlang模型真正放光芒的時(shí)候。
總結(jié)
以上是生活随笔為你收集整理的Erlang与java的内存架构比较的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: RMI原理及开发实例
- 下一篇: 实现java RPC框架