從Go語言角度淺談內(nèi)存分配
前言
相信各位小伙伴一定看過這樣的言論,某某B乎大佬xxx,發(fā)了一堆文字,一定要學(xué)好底層,一定要學(xué)好C語言!!,然后下面各種抬杠。
B乎大佬:C語言是最牛掰的,一定要從C語言開始學(xué)起。
杠精張三:學(xué)C有啥用,啥都干不成,直接學(xué)Java,然后上框架,直接開始開發(fā)。
杠精李四:@杠精張三,你會懂C嗎,瞎胡扯,xxx一堆理由,反正,C是一定要學(xué)的,基礎(chǔ)一定要打好。
...各路杠精大V正在趕來...
杠精王五:PHP萬歲,PHP NB,PHP天下第一。
嗯...,可能各位小伙伴或多或少,都看到過這些言論,作為吃瓜群眾,我們樂呵樂呵就好了,咱們回歸正題叭!!
是否需要學(xué)習(xí)C語言,我的回答是,不是必要的,但是需要懂為什么要學(xué)習(xí)C語言。
為什么要學(xué)習(xí)C語言
嗯,,,今年是2020年,要是從目前的各種開發(fā)項(xiàng)目中開說,C語言的確是用的很少,除了嵌入式等一些一定領(lǐng)域,基本很少能見到C的蹤影了,但是為什么還是一直能聽到xx說要學(xué)好C語言呢?
按照我的理解,其實(shí)學(xué)習(xí)C語言,學(xué)的并不是這個(gè)語言,而是這個(gè)語言背后所代表的一些東西,代表的一些設(shè)計(jì),代表的一些本質(zhì)。
C語言學(xué)的好,究竟會帶來什么優(yōu)勢
相信不少萌新在群里可能聽到某個(gè)大佬說,我一星期學(xué)完了xx語言,然后直接上手干活,然后你默默的說了一句,裝13,也可能,你們就在群里直接杠起來了。
那么,真的可以說,一周,或者兩周時(shí)間,學(xué)會一門語言嗎?。
我可以負(fù)責(zé)任的,告訴你,絕對沒問題,但是需要建立在強(qiáng)大的基礎(chǔ)上。
而指針,是一個(gè)特別重要的基礎(chǔ),現(xiàn)在不管哪個(gè)語言,其實(shí)本質(zhì)都是指針的應(yīng)用,只不過是封裝的簡單了而已。
但是這造成的就是根基如果不穩(wěn),就會造成一些莫名奇妙并且不懂的問題,尤其是對萌新來說。
所以,不管現(xiàn)在不管在任何階段,沒有學(xué)習(xí)C語言的一定要學(xué)學(xué)C,撿起曾經(jīng)丟下的重要的基礎(chǔ)。
那么,就先聽我簡單的入門一下吧。
所需要的技術(shù)棧
本次使用的技術(shù)棧是Go語言,理論來說是用C語言的,但是因?yàn)樵谥羔樳@一塊入門時(shí),Go和C的本質(zhì)基本一樣,所以就采用更加人性化的Go語言。
后期會在加上Python,和Go對比一下,區(qū)別在哪,看看燒了一把火的Python是如何分配內(nèi)存的。
當(dāng)前,在看此文章時(shí),我還是建議小伙伴有一定基礎(chǔ)的,至少能看懂怎么定義變量啥的都行。
操作系統(tǒng)各硬件的關(guān)系
首先,我們需要了解一下計(jì)算機(jī)主要組成部分。
首先,簡單的說,至少由 CPU 內(nèi)存條 硬盤 顯卡 顯示器 操作系統(tǒng)(Linux,Windowns)等。
那么這些硬件是如何互相配合的呢。
嗯...大概是這樣子的,有點(diǎn)丑。
簡而言之就是:
- 系統(tǒng)上的每個(gè)應(yīng)用(qq,微信,等)想要讓電腦播放音樂了,顯示器顯示個(gè)東西了,像硬盤寫入個(gè)文件了,都需要經(jīng)過操作系統(tǒng)的同意。
- 操作系統(tǒng)調(diào)用CPU完成指令的執(zhí)行,CPU將打開的應(yīng)用讀取到內(nèi)存條中,所以,為什么原來在機(jī)械硬盤會那么卡,機(jī)械太慢了,現(xiàn)在的固態(tài)嗖嗖嗖的就完成了硬盤數(shù)據(jù)到內(nèi)存條數(shù)據(jù)的轉(zhuǎn)移。
- CPU分析讀取到內(nèi)存條中的應(yīng)用數(shù)據(jù),如果是CPU處理的數(shù)據(jù),自己拿走計(jì)算,如果是顯卡處理的數(shù)據(jù),調(diào)用給顯卡計(jì)算,如果是聲音數(shù)據(jù),給聲卡計(jì)算,等。
- 通過以上協(xié)調(diào),整個(gè)應(yīng)用基本就能跑起來了,如果需要將數(shù)據(jù)寫入硬盤,CPU在將內(nèi)存條中的寫入硬盤就行了。
好嘞,通過上述,我們基本可以了解到操作系統(tǒng)和各硬件的協(xié)調(diào)關(guān)系。
悄悄的說個(gè)秘密咯,我們寫的代碼,基本都是運(yùn)行在內(nèi)存條中的呢,同理,上述所說的應(yīng)用,基本也是將應(yīng)用的代碼跑在內(nèi)存條中的。
內(nèi)存條
沒錯(cuò),就是這玩意,內(nèi)存條。
同理,我還還可以這樣理解內(nèi)存條內(nèi)部的結(jié)構(gòu)。
我們可以將內(nèi)存條理解成一個(gè)個(gè)房子,就像這樣。
依然還是很丑...
但是我們的內(nèi)存條是有的坐標(biāo)的,也叫地址,每個(gè)小格子里放著一個(gè)個(gè)的值。
但是通常情況下,我們都是平面圖理解的,就像這樣。
地址(坐標(biāo))一般以十六進(jìn)制表示,值該是啥就是傻。
代碼簡述
我們來看一段非常短Go的代碼。
聲明一個(gè)age變量并且賦值為18,并且輸出。
- package main
- import "fmt"
- func main() {
- var age int = 18
- fmt.Println("我今年:",age,"歲")
- }
在內(nèi)存中如何表示。
我們的變量名age指向了0x1001地址,并且輸出了0x0001存儲的值。
就像這樣。
注:一定要理解這句話,變量名指向的就是內(nèi)存條上的地址。
上述age指向就是地址0x1001。
但是我們在fmt.Println("我今年:",age,"歲")打印時(shí),我們打印的是地址里面的值。
同理,我們在賦值,交換變量時(shí),還是是地址里面的值。
例如:
上述代碼內(nèi)存分配圖。
age2會重新申請一個(gè)地址存儲age的值18。
可能有時(shí)候可能會有人問,星期八,有沒有這種情況,他倆同時(shí)指向一個(gè)內(nèi)存,這種不是更省內(nèi)存嘛。
結(jié)果:當(dāng)然會,這種情況,我們后面會講到的,現(xiàn)在能看懂就行,一步一步來。
結(jié)論
變量名指向的是內(nèi)存地址。
我們在賦值時(shí),或者打印等操作變量時(shí),操作的是地址上面的值。
本文轉(zhuǎn)載自微信公眾號「 Go語言進(jìn)階學(xué)習(xí)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 Go語言進(jìn)階學(xué)習(xí)公眾號。