簡析Go與Java內(nèi)存管理的差異

前 言?

從實(shí)踐中看,Golang(以下簡稱Go)應(yīng)用程序比Java占用更少的內(nèi)存肴楷,這與它們的運(yùn)行時(shí)環(huán)境有關(guān)珍坊,其運(yùn)行時(shí)自帶了內(nèi)存動態(tài)分配和自動垃圾回收的管理機(jī)制种蘸,本文通過分析Go與Java在內(nèi)存管理機(jī)制上的差異渗钉,以期對兩者在運(yùn)行時(shí)內(nèi)存方面有更進(jìn)一步的認(rèn)識鳄橘。本文以Go(1.12)和當(dāng)前使用較多的JDK8 HotSpot VM為例進(jìn)行說明瘫怜。

本篇文章包含以下內(nèi)容:

介紹Go與Java的運(yùn)行時(shí)內(nèi)存結(jié)構(gòu)差異

介紹Go與Java的內(nèi)存資源占用差異

介紹Go與Java如何為對象分配內(nèi)存

介紹Go與Java的內(nèi)存回收策略差異

內(nèi)存結(jié)構(gòu)差異

應(yīng)用程序要能在linux系統(tǒng)上運(yùn)行(其他平臺類似),其可執(zhí)行文件要求符合ELF規(guī)范(Executable and Linkable Format,可執(zhí)行和可鏈接格式)暗挑。操作系統(tǒng)加載目標(biāo)可執(zhí)行文件到內(nèi)存中并以獨(dú)立進(jìn)程方式運(yùn)行程序炸裆。

操作系統(tǒng)為每個進(jìn)程分配一個連續(xù)的虛擬內(nèi)存地址空間烹看,并將該進(jìn)程內(nèi)存空間劃分成多個不同用途的邏輯區(qū)域听系。JVM進(jìn)程以及Go進(jìn)程的內(nèi)存結(jié)構(gòu)如下圖所示:

圖1

Java用戶程序是運(yùn)行在Java虛擬機(jī)(以下簡稱“JVM”)之上的,從上圖我們看到用戶程序的字節(jié)碼指令并沒有存儲到JVM進(jìn)程的堆空間或者text段中毕源。實(shí)際上霎褐,虛擬機(jī)將用戶程序字節(jié)碼放在了使用本地直接內(nèi)存實(shí)現(xiàn)的方法區(qū)中冻璃,并不占用虛擬機(jī)的堆內(nèi)存省艳。

JVM的堆空間保存Java用戶程序運(yùn)行時(shí)創(chuàng)建的對象和字符串常量池等數(shù)據(jù)赖晶,椂舨澹空間則為Java線程提供了私有的內(nèi)存區(qū)域胳嘲。在HotSpot VM的實(shí)現(xiàn)中胎围,Java線程棧使用操作系統(tǒng)棧和線程模型表示白魂,且Java方法與本地方法共享同一個棧區(qū)福荸。因此虛擬機(jī)棧與本地方法棧其實(shí)是同一個區(qū)域敬锐。

Go與Java有較大不同台夺,Go進(jìn)程空間的text段不但保存了內(nèi)置的運(yùn)行時(shí)機(jī)器指令,而且還有用戶程序的機(jī)器指令(Go在編譯時(shí)就已確定)。堆內(nèi)存區(qū)則為用戶程序創(chuàng)建對象提供了存儲空間冤灾。Go天然支持并發(fā)編程模型韵吨,采用了系統(tǒng)線程與用戶線程(goroutine)相結(jié)合的實(shí)現(xiàn)機(jī)制归粉,進(jìn)程椪到剑空間為系統(tǒng)線程提供了棧內(nèi)存绢掰,而用戶線程棧的內(nèi)存默認(rèn)從堆中分配。

Java內(nèi)存結(jié)構(gòu)?

?1. 運(yùn)行時(shí)內(nèi)存?

Java程序的運(yùn)行時(shí)內(nèi)存被劃分為元數(shù)據(jù)區(qū)(方法區(qū))顾复、堆萧芙、虛擬機(jī)棧双揪、本地方法棧渔期、程序計(jì)數(shù)器5個部分疯趟,這可以看作是JVM對進(jìn)程可用堆信峻、楉镂瑁空間進(jìn)行的二次分配矾策,以滿足運(yùn)行Java用戶程序的內(nèi)存需求贾虽。其內(nèi)存結(jié)構(gòu)如下圖所示:


圖2

上圖中堆內(nèi)存對應(yīng)了圖1中JVM的堆內(nèi)存,虛擬機(jī)棧地粪、本地方法棧蟆技、程序計(jì)數(shù)器則對應(yīng)了圖1中JVM的棧區(qū)质礼,元數(shù)據(jù)區(qū)則是JVM另外開辟的內(nèi)存塊眶蕉。

·?元數(shù)據(jù)區(qū)是JVM向操作系統(tǒng)申請的堆外內(nèi)存造挽,用于實(shí)現(xiàn)“方法區(qū)”饭入,主要存儲虛擬機(jī)加載class的類信息、JIT編譯的代碼毁欣、運(yùn)行時(shí)常量池等數(shù)據(jù)饭耳,其默認(rèn)大小由系統(tǒng)的可用物理內(nèi)存上限限制寞肖。

·?堆內(nèi)存是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動時(shí)創(chuàng)建觅赊。它存放了包括幾乎所有的Java對象以及數(shù)組吮螺,這也是垃圾收集器關(guān)注的主要內(nèi)存區(qū)。由于逃逸分析等優(yōu)化技術(shù)嘀掸,對象也有可能被分配到棧上泉蝌。

·?虛擬機(jī)棧即我們常說的椑嬗耄空間粥鞋,其生命周期與線程相同呻粹。線程的椀茸牵空間存儲了方法調(diào)用的棧幀筹燕,每個棧幀則存儲局部變量表撒踪、操作數(shù)棧制妄、動態(tài)鏈接耕捞、方法出口等信息。

·?本地方法棧為JVM使用到的Native方法提供內(nèi)存空間敞映,而虛擬機(jī)棧為JVM執(zhí)行Java方法提供內(nèi)存空間振愿。HotSpot將虛擬機(jī)棧與本地方法棧合并管理。

·?程序計(jì)數(shù)器是一塊較小的內(nèi)存空間孩哑,用來指向當(dāng)前線程需要執(zhí)行的下一條字節(jié)碼指令横蜒。

元數(shù)據(jù)區(qū)丛晌、堆內(nèi)存為所有線程共享澎蛛,多線程訪問時(shí)需要進(jìn)行同步控制谋逻。虛擬機(jī)棧毁兆、本地方法棧气堕、程序計(jì)數(shù)器都是線程私有的內(nèi)存空間(堆的TLAB空間也是線程私有的空間)茎芭,訪問時(shí)無需加鎖骗爆,速度很快煮寡。


?2.? 分代的堆內(nèi)存?

Java用戶程序創(chuàng)建的對象主要存放在Java堆內(nèi)存中幸撕,操作非常頻繁坐儿,而且大部分對象的生命周期都很短暫貌矿。根據(jù)對象存活的特點(diǎn)逛漫,Java堆空間進(jìn)一步劃分為新生代和老年代酌毡,其中新生代又可以細(xì)分為eden區(qū)和兩塊相等大小的survivor區(qū)枷踏。JVM根據(jù)對象根據(jù)存活周期將其存放在不同的內(nèi)存代中旭蠕,不同的內(nèi)存代可以采用不同的垃圾收集器回收內(nèi)存下梢。如下圖所示:

圖3

·?新生代將內(nèi)存劃分為eden空間和兩塊較小的survivor空間孽江,每次使用eden和其中一塊survivor岗屏。當(dāng)回收時(shí),將eden和survivor中還存活著的對象一次性地復(fù)制到另外一塊survivor空間上暇屋,最后清理掉eden和剛才用過的survivor空間咐刨,這為新生代“標(biāo)記-復(fù)制”回收內(nèi)存提供算法實(shí)現(xiàn)便捷性定鸟。eden區(qū)與survivor區(qū)的大小比例是8:1:1。

·?老年代一般存放存活周期較長的對象以及大對象。老年代采用“標(biāo)記-清除”或“標(biāo)記-整理”算法回收內(nèi)存季眷。

·?新建對象總是優(yōu)先在新生代的eden區(qū)中分配子刮,“熬過”多次GC的對象可以從新生代晉升到老年代话告。

Go內(nèi)存結(jié)構(gòu)

?1.? 運(yùn)行時(shí)內(nèi)存?

Go的運(yùn)行時(shí)內(nèi)存就是操作系統(tǒng)分配給進(jìn)程空間的堆、棧內(nèi)存裳朋,在堆內(nèi)存的使用上不像JVM分代管理鲤嫡,而是采用分層級的內(nèi)存管理模式。


?2.? 分層級的堆內(nèi)存?

Go的堆內(nèi)存直接采用了TCMalloc庫的內(nèi)存管理模型纺裁。TCMalloc庫是Google開發(fā)的現(xiàn)代內(nèi)存分配器栋豫,其基本特征是內(nèi)存分層級谚殊、對抗內(nèi)存碎片以及快速分配等丛肢。Go語言根據(jù)自身需求對TCMalloc做了很多優(yōu)化摔踱,但仍保留了其基本架構(gòu)蛹批。

Go的內(nèi)存分配器是分層級的腐芍,由mcache/mcentral/mheap 三個組件構(gòu)成猪勇。因此整個堆內(nèi)存結(jié)構(gòu)可以看成是三層級的內(nèi)存模型,其結(jié)構(gòu)如下圖所示:

圖4

·?緩存組件mcache與工作線程(goroutine)綁定椅您,是goroutine私有的內(nèi)存空間。在mcache中為對象分配內(nèi)存時(shí)员舵,無需競爭马僻,性能很高。

·?中間組件mcentral 只負(fù)責(zé)一種規(guī)格(size class)的內(nèi)存塊仍秤,為mcache緩存組件提供備用的特定規(guī)格的可用空間。mcache的內(nèi)存擴(kuò)容請求會被分散到不同的mcentral 組件上可很,以減小共享內(nèi)存的競爭鎖粒度诗力。

·?堆組件mheap負(fù)責(zé)管理用戶程序的所有可用堆內(nèi)存空間以及為大對象直接分配內(nèi)存。它為上層組件提供擴(kuò)容支持。當(dāng)空間不足時(shí)苇本,mheap組件向操作系統(tǒng)申請內(nèi)存袜茧。


中間組件mcentral、堆組件mheap為所有工作線程(goroutine)所共享瓣窄,所以在內(nèi)存分配時(shí)通常存在同步競爭的情況笛厦。

“多出來”的方法區(qū)

Go程序指令被操作系統(tǒng)加載到內(nèi)存并保存在text段中俺夕,其大小在運(yùn)行時(shí)基本是確定的。

而JVM的text段存儲的是虛擬機(jī)本身的指令數(shù)據(jù)件甥,Java用戶程序的字節(jié)碼被加載并存儲在堆外內(nèi)存的元數(shù)據(jù)區(qū)(方法區(qū))中。Java字節(jié)碼的加載過程如下圖所示:

圖5

·?在程序啟動导帝、運(yùn)行期間虐秦,JVM中的類裝載器子系統(tǒng)按需動態(tài)加載類文件(包括Java API基礎(chǔ)類庫、用戶程序class文件暮现、第三方依賴庫等)塘幅、以及由字節(jié)碼框架動態(tài)生成的類信息呼伸,這些數(shù)據(jù)經(jīng)加載铃辖、驗(yàn)證穴翩、準(zhǔn)備背蟆、解析伦糯、初始化等一系列過程最終都會保存在方法區(qū)中惭等。

·?程序運(yùn)行時(shí)秤茅,執(zhí)行引擎中的解釋器解釋執(zhí)行方法區(qū)中的字節(jié)碼指令∏说混合模式下的JIT編譯器將探測到的熱點(diǎn)代碼編譯為本地可執(zhí)行的機(jī)器指令达罗,編譯的機(jī)器指令也保存在方法區(qū)中。

隨著程序不斷運(yùn)行膨蛮,方法區(qū)所占的內(nèi)存空間可能會越來越大持偏,存儲的數(shù)據(jù)有時(shí)候能達(dá)到數(shù)百兆;而對該內(nèi)存區(qū)域中類型卸載的條件又比較苛刻附帽,內(nèi)存回收效率并不如堆內(nèi)存理想。

這“多出來”的用于存儲Java用戶程序字節(jié)碼指令的區(qū)域是Java程序比Go消耗更多內(nèi)存的一個重要因素抽莱。

對象內(nèi)存分配差異

不同的內(nèi)存結(jié)構(gòu)決定了對象內(nèi)存分配方式的差異偶惠,也會給垃圾回收帶來影響瘾腰。Go以及Java都支持變量的逃逸分析析藕,逃逸到棧上的對象會隨著方法退出而自然回收账胧,而分配到堆內(nèi)存的對象則需要垃圾收集器回收才能釋放出內(nèi)存空間。因而我們更多關(guān)注對象在堆上分配空間的過程先紫。

? Java對象??

JVM會為新創(chuàng)建的線程在stack棧區(qū)分配一塊私有的線程椫文啵空間。某一個線程中創(chuàng)建的Java對象可能被分配在新生代遮精,也可能分配在老年代居夹,其具體的分配方法如下圖所示:

圖6

JVM執(zhí)行線程的創(chuàng)建對象指令,會向堆內(nèi)存申請對象空間本冲。堆內(nèi)存被所有線程共享意狠,在為對象分配空間時(shí)需要同步鎖定,這會降低內(nèi)存分配的效率顶瞒。用戶可以設(shè)置-XX: +UseTLAB參數(shù)啟用TLAB功能,這樣JVM總是優(yōu)先嘗試在當(dāng)前線程的TALB空間為對象分配內(nèi)存。TLAB(Thread-Local Allocation Buffer,線程本地分配緩沖區(qū))是JVM預(yù)先為每一個線程在堆區(qū)中劃分的一小塊私有內(nèi)存空間常柄,線程分配的對象空間總是在自己的TLAB上分配,無需加鎖镀岛。如果TLAB內(nèi)存用完了則重新申請一塊新的TLAB匆赃。如果在TLAB中分配失敗猪杭,則會嘗試在新生代中繼續(xù)分配操作麻裳。一般過程如下所示:

1)首先檢查該類是否已加載、解析、初始化拢肆。如果沒有鄙才,則執(zhí)行類加載的過程叙甸。

2)分配對象內(nèi)存時(shí)僚祷,檢查是否啟用-XX: +UseTLAB參數(shù)。如果啟用TLAB,則直接從當(dāng)前線程的TLAB空間以lock free方式分配指定大小的內(nèi)存塊,速度很快憨愉。

■? 如果TLAB剩余空間大于其可浪費(fèi)空間閾值径密,則直接在新生代中分配。

■? 否則躺孝,JVM會嘗試為當(dāng)前線程重新開辟一塊TLAB空間享扔。

3)如果未啟用UseTLAB或者TLAB分配失敗,JVM將繼續(xù)在eden區(qū)或老年代上為對象分配空間植袍,這時(shí)需要做同步操作惧眠。

4)對象內(nèi)存分配成功后,JVM初始化對象零值于个、設(shè)置對象頭等元信息氛魁,執(zhí)行對象初始化方法,最后將對象引用壓入線程的棧內(nèi)存中。


新建對象總是分配在新生代的eden區(qū)秀存,當(dāng)空間不夠時(shí)捶码,會存放在老年代中。如果剩余空間還是不夠或链,JVM會申請擴(kuò)容或觸發(fā)一次GC回收內(nèi)存后繼續(xù)在各個內(nèi)存代中嘗試分配惫恼。

Java大對象的分配過程稍有不同,JVM總是直接在老年代中為其分配存儲空間澳盐。我們可以通過-XX:PretenureSizeThreshold參數(shù)來設(shè)定大對象的閾值祈纯,該參數(shù)默認(rèn)值為0,說明對象總是先在eden區(qū)分配洞就,不管這個對象有多大盆繁。

?Go對象??

Go內(nèi)存分配器管理span以及object兩種類型的內(nèi)存塊掀淘。span是Go內(nèi)存管理的基本單元旬蟋,由多個地址連續(xù)的頁(8k大小的page內(nèi)存塊)組成的?塊內(nèi)存。object則是將span按照特定規(guī)格(size class)切分成的多個?塊革娄,每個?塊都可以用來存儲?個對象倾贰。

Go的object內(nèi)存塊大小為8字節(jié)的整倍數(shù),被劃分為67種規(guī)格拦惋。Go對象的內(nèi)存分配就是從有限的67種規(guī)格中找出與對象大小最合適的一塊可用內(nèi)存塊的過程匆浙。Go使用“空閑列表”方式管理可分配的內(nèi)存空間,相同規(guī)格的內(nèi)存塊連接成一個雙向鏈表厕妖。以下是Go object的size class對應(yīng)表首尼,其中包含66種規(guī)格,另外一種規(guī)格是大于32KB的大對象:

根據(jù)不同對象的規(guī)格大小,Go內(nèi)存分配器有不同的內(nèi)存分配邏輯言秸。比如零長度對象由于沒有可讀寫內(nèi)容软能,在分配時(shí)不同類型可能指向同一位置,如struct{}與[0]int举畸。內(nèi)存分配器會將小于16字節(jié)且不包含指針(noscan)的微小對象組合起來查排,并嘗試用單個object內(nèi)存塊存儲以減少內(nèi)存浪費(fèi)。32KB以內(nèi)大小的小對象使用mcache組件進(jìn)行分配抄沮,大于32KB的大對象直接在mheap組件管理的堆上分配跋核。


用戶程序中創(chuàng)建的對象大部分是小對象,這也是內(nèi)存分配器的重心所在叛买,小對象分配在每個goroutine mcache中避免了競爭鎖提升了分配效率砂代。如前所述,Go內(nèi)存分配器采用分層級組件的方式來管理應(yīng)用的堆內(nèi)存率挣,為小對象分配內(nèi)存需要多級組件相互協(xié)作完成刻伊。分配過程如下圖所示:

圖7

·?mcache緩存是goroutine的私有內(nèi)存空間,直接為當(dāng)前goroutine無鎖分配小對象的內(nèi)存塊,速度很快娃圆。內(nèi)存分配器首先根據(jù)對象大小獲取mcache中對應(yīng)size class的span鏈表玫锋,并從表頭span中提取object塊進(jìn)行分配。

·?如果分配器發(fā)現(xiàn)mcache下沒有對應(yīng)規(guī)格的可用span資源讼呢,則會嘗試從堆區(qū)相應(yīng)class的mcentral區(qū)域中申請擴(kuò)容(mcentral是所有線程共享撩鹿,在為mcache擴(kuò)容時(shí)總是會先lock)。分配器將申請到的span資源鏈接到mcache鏈表悦屏,繼續(xù)為對象分配object塊空間节沦。

·?如果mcentral中沒有找到可用的內(nèi)存塊,分配器會向mheap申請擴(kuò)容础爬,擴(kuò)容成功后繼續(xù)為對象分配內(nèi)存甫贯。

對于大對象,Go的內(nèi)存分配器直接在mheap分配內(nèi)存看蚜,如果沒有找到合適的span內(nèi)存塊叫搁,分配器將向操作系統(tǒng)申請擴(kuò)容后繼續(xù)分配。提取的span內(nèi)存塊如果超過了對象規(guī)格所需的頁數(shù)供炎,分配器將嘗試分割該span合適大小分配給對象渴逻,并合并剩余的空間歸還給mheap管理,以減少堆內(nèi)存碎片音诫。


由上可知惨奕,小對象內(nèi)存分配,Go mcache方式與Java TLAB方式相似竭钝,都是從堆內(nèi)存中為線程劃分私有空間以便進(jìn)行快速分配梨撞,但是仍然會有所差異:

垃圾收集差異

內(nèi)存結(jié)構(gòu)劃分、對象分配方式與垃圾收集策略密切相關(guān)香罐,而且自動GC很大程度上會成為影響系統(tǒng)性能的瓶頸卧波。Go與Java的GC策略是判斷對象是否存活,并對其進(jìn)行標(biāo)記穴吹,或采用“復(fù)制”算法幽勒、“清除”算法、“整理”算法等完成不可引用對象的內(nèi)存回收操作港令。目前垃圾收集過程中總是會遇到STW(stop the world)的問題啥容。

Java GC

·垃圾收集器一覽

JVM的垃圾收集是分代的收集。比如新生代采用“標(biāo)記-復(fù)制”算法進(jìn)行回收顷霹,老年代通常使用“標(biāo)記-清理”或“標(biāo)記-整理”算法咪惠。其中在G1收集器下,內(nèi)存的劃分又稍有不同了淋淀。

以下是JVM中主要的垃圾收集器實(shí)現(xiàn)遥昧,其中JDK8默認(rèn)GC組合是Parallel Scavenge(新生代)和Parallel Old(老年代):

?· GC觸發(fā)時(shí)機(jī)一覽

JVM的GC策略根據(jù)內(nèi)存分代可以分為Minor GC(新生代垃圾收集)和Full GC(Major GC,老年代垃圾收集)兩類。它們的觸發(fā)時(shí)機(jī)一般如下表所示:

?Go GC?

Go只有一種垃圾收集器,其基于優(yōu)化改進(jìn)的“標(biāo)記-清除”算法炭臭,特征為“非分代永脓、非緊縮、寫屏障鞋仍、三色標(biāo)記常摧、并發(fā)標(biāo)記清理”。Go的“非分代”內(nèi)存管理使得Go并不需要實(shí)現(xiàn)多種GC算法策略威创,“非緊縮”的特征使得回收的內(nèi)存塊非常容易的復(fù)用,較少產(chǎn)生內(nèi)存碎片肚豺,基本上不需要壓縮整理溃斋。Go的垃圾收集器與JVM中的CMS垃圾收集器原理上是非常相似的隐岛。

·? GC中的STW問題

垃圾收集器在回收對象內(nèi)存的過程中,總是需要掛起所有的用戶線程(即STW,stop the world),以避免GC線程在回收時(shí)對象的引用關(guān)系還在不斷變化導(dǎo)致回收結(jié)果不準(zhǔn)確旗们。但是STW可能會因GC時(shí)間過長而使得用戶線程長時(shí)間的停頓锹锰,這對追求響應(yīng)速度的程序來說將是令人難以接收的恃慧。Go GC的目標(biāo)就是盡量減小STW的時(shí)間园蝠,以使得程序能夠獲取最大限度的響應(yīng)速度。

Go GC線程與用戶線程是并發(fā)的痢士,其過程可以分為如下四個階段:

■ Sweep termination:清理掉意外遺留的span內(nèi)存塊彪薛,只有上一次的GC清除工作完成了才能開始下一次GC。

■?Mark:

1)初始標(biāo)記怠蹂,需要STW善延。準(zhǔn)備GC Roots對象的掃描、開啟寫屏障等城侧。

2)并發(fā)標(biāo)記易遣,GC Roots到所有的對象的可達(dá)性分析,采用三色標(biāo)記法嫌佑。

■?Mark termination:

重新標(biāo)記豆茫,需要STW。重新掃描部分GC Roots對象屋摇,修正并發(fā)標(biāo)記期間因用戶線程繼續(xù)運(yùn)行而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄揩魂。

■?Sweep:

根據(jù)標(biāo)記結(jié)果并發(fā)清除,回收內(nèi)存炮温。

可見火脉,在初始標(biāo)記以及重新標(biāo)記期間仍然存在STW問題。Go GC雖然沒有完全消除STW柒啤,但在整個GC回收周期中倦挂,已將STW局限在有限的2個階段,這讓程序?qū)崟r(shí)性有了很大改善白修。

·GC觸發(fā)時(shí)機(jī)一覽

Go的堆內(nèi)存沒有分代妒峦,每次GC時(shí)都要回收整個堆中的對象。

上文我們只對Go與Java在內(nèi)存管理方面做了一個簡要的比較分析兵睛,其中還有很多方面以及細(xì)節(jié)并未展開或涉及肯骇。我們看到了Go與Java在內(nèi)存管理上采用的不同策略所帶來的一些影響:Java的分代內(nèi)存管理支持各個內(nèi)存代選擇合適的GC算法實(shí)現(xiàn)窥浪,通常GC只需要對某一個內(nèi)存代進(jìn)行回收;Go對整塊堆內(nèi)存分層級管理笛丙,GC時(shí)就不得不掃描整塊區(qū)域漾脂。Java與Go為了實(shí)現(xiàn)對象空間的快速分配,都為線程分配了一塊私有堆內(nèi)存胚鸯。Java分配確定的大小對象內(nèi)存骨稿,回收時(shí)更容易造成堆內(nèi)存碎片問題。Go按size class的分塊對象內(nèi)存模式雖然在重用性上得到了改善姜钳,但是又造成了一些浪費(fèi)坦冠。可見Go與Java 在內(nèi)存管理上各有特點(diǎn)哥桥。

Go語言社區(qū)活躍辙浑,生態(tài)也在逐漸繁榮。Go與Java各有優(yōu)勢拟糕,兩者之間也有許多可以相互借鑒之處判呕,因此它們未來的發(fā)展也非常值得期待。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末送滞,一起剝皮案震驚了整個濱河市侠草,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌犁嗅,老刑警劉巖边涕,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愧哟,居然都是意外死亡奥吩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門蕊梧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腮介,你說我怎么就攤上這事肥矢。” “怎么了叠洗?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵甘改,是天一觀的道長。 經(jīng)常有香客問我灭抑,道長十艾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任腾节,我火速辦了婚禮忘嫉,結(jié)果婚禮上荤牍,老公的妹妹穿的比我還像新娘。我一直安慰自己庆冕,他們只是感情好康吵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著访递,像睡著了一般晦嵌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拷姿,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天惭载,我揣著相機(jī)與錄音,去河邊找鬼响巢。 笑死描滔,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抵乓。 我是一名探鬼主播伴挚,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼灾炭!你這毒婦竟也來了茎芋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蜈出,失蹤者是張志新(化名)和其女友劉穎田弥,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铡原,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡偷厦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了燕刻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只泼。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖卵洗,靈堂內(nèi)的尸體忽然破棺而出请唱,到底是詐尸還是另有隱情,我是刑警寧澤过蹂,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布十绑,位于F島的核電站,受9級特大地震影響酷勺,放射性物質(zhì)發(fā)生泄漏本橙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一脆诉、第九天 我趴在偏房一處隱蔽的房頂上張望甚亭。 院中可真熱鬧贷币,春花似錦、人聲如沸狂鞋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骚揍。三九已至字管,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間信不,已是汗流浹背嘲叔。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抽活,地道東北人硫戈。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像下硕,于是被迫代替她去往敵國和親丁逝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容