真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

go語言的class go語言的未來

(十一)golang 內(nèi)存分析

編寫過C語言程序的肯定知道通過malloc()方法動(dòng)態(tài)申請(qǐng)內(nèi)存,其中內(nèi)存分配器使用的是glibc提供的ptmalloc2。 除了glibc,業(yè)界比較出名的內(nèi)存分配器有Google的tcmalloc和Facebook的jemalloc。二者在避免內(nèi)存碎片和性能上均比glic有比較大的優(yōu)勢(shì),在多線程環(huán)境中效果更明顯。

槐蔭網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),槐蔭網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為槐蔭成百上千提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營(yíng)銷網(wǎng)站建設(shè)要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的槐蔭做網(wǎng)站的公司定做!

Golang中也實(shí)現(xiàn)了內(nèi)存分配器,原理與tcmalloc類似,簡(jiǎn)單的說就是維護(hù)一塊大的全局內(nèi)存,每個(gè)線程(Golang中為P)維護(hù)一塊小的私有內(nèi)存,私有內(nèi)存不足再從全局申請(qǐng)。另外,內(nèi)存分配與GC(垃圾回收)關(guān)系密切,所以了解GC前有必要了解內(nèi)存分配的原理。

為了方便自主管理內(nèi)存,做法便是先向系統(tǒng)申請(qǐng)一塊內(nèi)存,然后將內(nèi)存切割成小塊,通過一定的內(nèi)存分配算法管理內(nèi)存。 以64位系統(tǒng)為例,Golang程序啟動(dòng)時(shí)會(huì)向系統(tǒng)申請(qǐng)的內(nèi)存如下圖所示:

預(yù)申請(qǐng)的內(nèi)存劃分為spans、bitmap、arena三部分。其中arena即為所謂的堆區(qū),應(yīng)用中需要的內(nèi)存從這里分配。其中spans和bitmap是為了管理arena區(qū)而存在的。

arena的大小為512G,為了方便管理把a(bǔ)rena區(qū)域劃分成一個(gè)個(gè)的page,每個(gè)page為8KB,一共有512GB/8KB個(gè)頁;

spans區(qū)域存放span的指針,每個(gè)指針對(duì)應(yīng)一個(gè)page,所以span區(qū)域的大小為(512GB/8KB)乘以指針大小8byte = 512M

bitmap區(qū)域大小也是通過arena計(jì)算出來,不過主要用于GC。

span是用于管理arena頁的關(guān)鍵數(shù)據(jù)結(jié)構(gòu),每個(gè)span中包含1個(gè)或多個(gè)連續(xù)頁,為了滿足小對(duì)象分配,span中的一頁會(huì)劃分更小的粒度,而對(duì)于大對(duì)象比如超過頁大小,則通過多頁實(shí)現(xiàn)。

根據(jù)對(duì)象大小,劃分了一系列class,每個(gè)class都代表一個(gè)固定大小的對(duì)象,以及每個(gè)span的大小。如下表所示:

上表中每列含義如下:

class: class ID,每個(gè)span結(jié)構(gòu)中都有一個(gè)class ID, 表示該span可處理的對(duì)象類型

bytes/obj:該class代表對(duì)象的字節(jié)數(shù)

bytes/span:每個(gè)span占用堆的字節(jié)數(shù),也即頁數(shù)乘以頁大小

objects: 每個(gè)span可分配的對(duì)象個(gè)數(shù),也即(bytes/spans)/(bytes/obj)waste

bytes: 每個(gè)span產(chǎn)生的內(nèi)存碎片,也即(bytes/spans)%(bytes/obj)上表可見最大的對(duì)象是32K大小,超過32K大小的由特殊的class表示,該class ID為0,每個(gè)class只包含一個(gè)對(duì)象。

span是內(nèi)存管理的基本單位,每個(gè)span用于管理特定的class對(duì)象, 跟據(jù)對(duì)象大小,span將一個(gè)或多個(gè)頁拆分成多個(gè)塊進(jìn)行管理。src/runtime/mheap.go:mspan定義了其數(shù)據(jù)結(jié)構(gòu):

以class 10為例,span和管理的內(nèi)存如下圖所示:

spanclass為10,參照class表可得出npages=1,nelems=56,elemsize為144。其中startAddr是在span初始化時(shí)就指定了某個(gè)頁的地址。allocBits指向一個(gè)位圖,每位代表一個(gè)塊是否被分配,本例中有兩個(gè)塊已經(jīng)被分配,其allocCount也為2。next和prev用于將多個(gè)span鏈接起來,這有利于管理多個(gè)span,接下來會(huì)進(jìn)行說明。

有了管理內(nèi)存的基本單位span,還要有個(gè)數(shù)據(jù)結(jié)構(gòu)來管理span,這個(gè)數(shù)據(jù)結(jié)構(gòu)叫mcentral,各線程需要內(nèi)存時(shí)從mcentral管理的span中申請(qǐng)內(nèi)存,為了避免多線程申請(qǐng)內(nèi)存時(shí)不斷的加鎖,Golang為每個(gè)線程分配了span的緩存,這個(gè)緩存即是cache。src/runtime/mcache.go:mcache定義了cache的數(shù)據(jù)結(jié)構(gòu)

alloc為mspan的指針數(shù)組,數(shù)組大小為class總數(shù)的2倍。數(shù)組中每個(gè)元素代表了一種class類型的span列表,每種class類型都有兩組span列表,第一組列表中所表示的對(duì)象中包含了指針,第二組列表中所表示的對(duì)象不含有指針,這么做是為了提高GC掃描性能,對(duì)于不包含指針的span列表,沒必要去掃描。根據(jù)對(duì)象是否包含指針,將對(duì)象分為noscan和scan兩類,其中noscan代表沒有指針,而scan則代表有指針,需要GC進(jìn)行掃描。mcache和span的對(duì)應(yīng)關(guān)系如下圖所示:

mchache在初始化時(shí)是沒有任何span的,在使用過程中會(huì)動(dòng)態(tài)的從central中獲取并緩存下來,跟據(jù)使用情況,每種class的span個(gè)數(shù)也不相同。上圖所示,class 0的span數(shù)比class1的要多,說明本線程中分配的小對(duì)象要多一些。

cache作為線程的私有資源為單個(gè)線程服務(wù),而central則是全局資源,為多個(gè)線程服務(wù),當(dāng)某個(gè)線程內(nèi)存不足時(shí)會(huì)向central申請(qǐng),當(dāng)某個(gè)線程釋放內(nèi)存時(shí)又會(huì)回收進(jìn)central。src/runtime/mcentral.go:mcentral定義了central數(shù)據(jù)結(jié)構(gòu):

lock: 線程間互斥鎖,防止多線程讀寫沖突

spanclass : 每個(gè)mcentral管理著一組有相同class的span列表

nonempty: 指還有內(nèi)存可用的span列表

empty: 指沒有內(nèi)存可用的span列表

nmalloc: 指累計(jì)分配的對(duì)象個(gè)數(shù)線程從central獲取span步驟如下:

將span歸還步驟如下:

從mcentral數(shù)據(jù)結(jié)構(gòu)可見,每個(gè)mcentral對(duì)象只管理特定的class規(guī)格的span。事實(shí)上每種class都會(huì)對(duì)應(yīng)一個(gè)mcentral,這個(gè)mcentral的集合存放于mheap數(shù)據(jù)結(jié)構(gòu)中。src/runtime/mheap.go:mheap定義了heap的數(shù)據(jù)結(jié)構(gòu):

lock: 互斥鎖

spans: 指向spans區(qū)域,用于映射span和page的關(guān)系

bitmap:bitmap的起始地址

arena_start: arena區(qū)域首地址

arena_used: 當(dāng)前arena已使用區(qū)域的最大地址

central: 每種class對(duì)應(yīng)的兩個(gè)mcentral

從數(shù)據(jù)結(jié)構(gòu)可見,mheap管理著全部的內(nèi)存,事實(shí)上Golang就是通過一個(gè)mheap類型的全局變量進(jìn)行內(nèi)存管理的。mheap內(nèi)存管理示意圖如下:

系統(tǒng)預(yù)分配的內(nèi)存分為spans、bitmap、arean三個(gè)區(qū)域,通過mheap管理起來。接下來看內(nèi)存分配過程。

針對(duì)待分配對(duì)象的大小不同有不同的分配邏輯:

(0, 16B) 且不包含指針的對(duì)象: Tiny分配

(0, 16B) 包含指針的對(duì)象:正常分配

[16B, 32KB] : 正常分配

(32KB, -) : 大對(duì)象分配其中Tiny分配和大對(duì)象分配都屬于內(nèi)存管理的優(yōu)化范疇,這里暫時(shí)僅關(guān)注一般的分配方法。

以申請(qǐng)size為n的內(nèi)存為例,分配步驟如下:

Golang內(nèi)存分配是個(gè)相當(dāng)復(fù)雜的過程,其中還摻雜了GC的處理,這里僅僅對(duì)其關(guān)鍵數(shù)據(jù)結(jié)構(gòu)進(jìn)行了說明,了解其原理而又不至于深陷實(shí)現(xiàn)細(xì)節(jié)。1、Golang程序啟動(dòng)時(shí)申請(qǐng)一大塊內(nèi)存并劃分成spans、bitmap、arena區(qū)域

2、arena區(qū)域按頁劃分成一個(gè)個(gè)小塊。

3、span管理一個(gè)或多個(gè)頁。

4、mcentral管理多個(gè)span供線程申請(qǐng)使用

5、mcache作為線程私有資源,資源來源于mcentral。

3、搜索class文件

gojvm目錄

1、搭建go環(huán)境

2、cmd命令行參數(shù)解析

3、搜索class文件

4、添加testOption 便于單元測(cè)試

5、解析classfile文件

6、運(yùn)行時(shí)數(shù)據(jù)區(qū)

7、指令集

8、解釋器

9、創(chuàng)建Class

10、類加載器

11、對(duì)象實(shí)例化new object

12、方法調(diào)用和返回

13 類初始化

14、jvm支持?jǐn)?shù)組

15、jvm支持字符串-數(shù)組擴(kuò)展

16、本地方法調(diào)用

17、ClassLoader原理

18、異常處理

19、 啟動(dòng)jvm

java jvm根據(jù)類路徑(class path)來搜索類,加載到內(nèi)存

可以通過 -Xbootclasspath 修改啟動(dòng)類路徑

參數(shù) -classpath /-cp

go語言不需要顯式實(shí)現(xiàn)接口

defer 確保異常及時(shí)處理

1、Entry搜索類路徑

2、DirEntry 搜索目錄下類路徑

3、ZipEntry 搜索zip或jar文件形式類路徑

4、CompositeEntry 組合類路徑

5、WildcardEntry 所有通配符下類路徑

Entry 類路徑查找

測(cè)試類

提交標(biāo)簽classpath

為什么要使用 Go 語言?Go 語言的優(yōu)勢(shì)在哪里

1. 保留但大幅度簡(jiǎn)化指針

Go語言保留著C中值和指針的區(qū)別,但是對(duì)于指針繁瑣用法進(jìn)行了大量的簡(jiǎn)化,引入引用的概念。所以在Go語言中,你幾乎不用擔(dān)心會(huì)因?yàn)橹苯硬僮鲀?nèi)寸而引起各式各樣的錯(cuò)誤。

2. 多參數(shù)返回

還記得在C里面為了回饋多個(gè)參數(shù),不得不開辟幾段指針傳到目標(biāo)函數(shù)中讓其操作么?在Go里面這是完全不必要的。而且多參數(shù)的支持讓Go無需使用繁瑣的exceptions體系,一個(gè)函數(shù)可以返回期待的返回值加上error,調(diào)用函數(shù)后立刻處理錯(cuò)誤信息,清晰明了。

3. Array,slice,map等內(nèi)置基本數(shù)據(jù)結(jié)構(gòu)

如果你習(xí)慣了Python中簡(jiǎn)潔的list和dict操作,在Go語言中,你不會(huì)感到孤單。一切都是那么熟悉,而且更加高效。如果你是C++程序員,你會(huì)發(fā)現(xiàn)你又找到了STL的vector 和 map這對(duì)朋友。

4. Interface

Go語言最讓人贊嘆不易的特性,就是interface的設(shè)計(jì)。任何數(shù)據(jù)結(jié)構(gòu),只要實(shí)現(xiàn)了interface所定義的函數(shù),自動(dòng)就implement了這個(gè)interface,沒有像Java那樣冗長(zhǎng)的class申明,提供了靈活太多的設(shè)計(jì)度和OO抽象度,讓你的代碼也非常干凈。千萬不要以為你習(xí)慣了Java那種一條一條加implements的方式,感覺還行,等接口的設(shè)計(jì)越來越復(fù)雜的時(shí)候,無數(shù)Bug正在后面等著你。

同時(shí),正因?yàn)槿绱耍珿o語言的interface可以用來表示任何generic的東西,比如一個(gè)空的interface,可以是string可以是int,可以是任何數(shù)據(jù)類型,因?yàn)檫@些數(shù)據(jù)類型都不需要實(shí)現(xiàn)任何函數(shù),自然就滿足空interface的定義了。加上Go語言的type assertion,可以提供一般動(dòng)態(tài)語言才有的duck typing特性, 而仍然能在compile中捕捉明顯的錯(cuò)誤。

5. OO

Go語言本質(zhì)上不是面向?qū)ο笳Z言,它還是過程化的。但是,在Go語言中, 你可以很輕易的做大部分你在別的OO語言中能做的事,用更簡(jiǎn)單清晰的邏輯。是的,在這里,不需要class,仍然可以繼承,仍然可以多態(tài),但是速度卻快得多。因?yàn)楸举|(zhì)上,OO在Go語言中,就是普通的struct操作。

6. Goroutine

這個(gè)幾乎算是Go語言的招牌特性之一了,我也不想多提。如果你完全不了解Goroutine,那么你只需要知道,這玩意是超級(jí)輕量級(jí)的類似線程的東西,但通過它,你不需要復(fù)雜的線程操作鎖操作,不需要care調(diào)度,就能玩轉(zhuǎn)基本的并行程序。在Go語言里,觸發(fā)一個(gè)routine和erlang spawn一樣簡(jiǎn)單?;旧弦莆誈o語言,以Goroutine和channel為核心的內(nèi)存模型是必須要懂的。不過請(qǐng)放心,真的非常簡(jiǎn)單。

7. 更多現(xiàn)代的特性

和C比較,Go語言完全就是一門現(xiàn)代化語言,原生支持的Unicode, garbage collection, Closures(是的,和functional programming language類似), function是first class object,等等等等。

看到這里,你可能會(huì)發(fā)現(xiàn),我用了很多輕易,簡(jiǎn)單,快速之類的形容詞來形容Go語言的特點(diǎn)。我想說的是,一點(diǎn)都不夸張,連Go語言的入門學(xué)習(xí)到提高,都比別的語言門檻低太多太多。在大部分人都有C的背景的時(shí)代,對(duì)于Go語言,從入門到能夠上手做項(xiàng)目,最多不過半個(gè)月。Go語言給人的感覺就是太直接了,什么都直接,讀源代碼直接,寫自己的代碼也直接。


新聞標(biāo)題:go語言的class go語言的未來
網(wǎng)頁地址:http://weahome.cn/article/dopchcp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部