欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

go語言內存分配方法,go語言內存占用

Go語言中new和 make的區(qū)別詳解

1、new 的主要特性

成都創(chuàng)新互聯(lián)成立于2013年,先為青秀等服務建站,青秀等地企業(yè),進行企業(yè)商務咨詢服務。為青秀企業(yè)網站制作PC+手機+微官網三網同步一站式服務解決您的所有建站問題。

首先 new 是內建函數,定義也很簡單:

func new(Type) *Type

內建函數 new 用來分配內存,第一個參數是一個類型,不是一個值,返回值是一個指向新分配類型零值的指針

實現(xiàn)一個類似 new 的功能:

func newInt() *int {

var i int

return i

}

someInt := newInt()

函數的功能跟 someInt := new(int) 一模一樣。定義 new 開頭的函數時,出于約定也應該返回類型的指針。

2、make 的主要特性

make 也是內建函數,定義比 new 多了一個參數,返回值也不同:

func make(Type, size IntegerType) Type

內建函數 make 用來為 slice,map 或 chan 類型分配內存和初始化一個對象(注意:只能用在這三種類型上),跟 new 類似,第一個參數也是一個類型而不是一個值,跟 new 不同的是,make 返回類型的引用而不是指針,而返回值也依賴于具體傳入的類型,具體說明如下:

Slice: 第二個參數 size 指定了長度,容量和長度相同。

可以傳入第三個參數來指定不同的容量值,但必須不能比長度值小。

比如 make([]int, 0, 10)

Map: 根據 size 大小來初始化分配內存,不過分配后的 map 長度為 0,如果 size 被忽略了,那么會在初始化分配內存時分配一個小尺寸的內存

Channel: 管道緩沖區(qū)依據緩沖區(qū)容量被初始化。如果容量為 0 或者忽略容量,管道沒有緩沖區(qū)。

3、總結

new 的作用是初始化一個指向類型的指針(*T),make 的作用是為 slice,map 或 chan 初始化并返回引用(T)。

go語言中怎么給結構體分配內存

隨便怎么寫啊,共享內存獲取到不是給你一個內存地址,這里稱之為des么,直接通過des地址訪問啊,比如你要寫2個結構體進去,第一個memcpy寫到des,第二個可以(memcpy到des+結構體大小)的地址指向的內存上,

Go語言有什么優(yōu)勢?

GO語言的優(yōu)勢:可直接編譯成機器碼,不依賴其他庫,glibc的版本有一定要求,部署就是扔一個文件上去就完成了。靜態(tài)類型語言,但是有動態(tài)語言的感覺,靜態(tài)類型的語言就是可以在編譯的時候檢查出來隱藏的大多數問題,動態(tài)語言的感覺就是有很多的包可以使用,寫起來的效率很高。語言層面支持并發(fā),這個就是Go最大的特色,天生的支持并發(fā),我曾經說過一句話,天生的基因和整容是有區(qū)別的,大家一樣美麗,但是你喜歡整容的還是天生基因的美麗呢?Go就是基因里面支持的并發(fā),可以充分的利用多核,很容易的使用并發(fā)。內置runtime,支持垃圾回收,這屬于動態(tài)語言的特性之一吧,雖然目前來說GC不算完美,但是足以應付我們所能遇到的大多數情況,特別是Go1.1之后的GC。簡單易學,Go語言的作者都有C的基因,那么Go自然而然就有了C的基因,那么Go關鍵字是25個,但是表達能力很強大,幾乎支持大多數你在其他語言見過的特性:繼承、重載、對象等。豐富的標準庫,Go目前已經內置了大量的庫,特別是網絡庫非常強大,我最愛的也是這部分。內置強大的工具,Go語言里面內置了很多工具鏈,最好的應該是gofmt工具,自動化格式化代碼,能夠讓團隊review變得如此的簡單,代碼格式一模一樣,想不一樣都很困難。跨平臺編譯,如果你寫的Go代碼不包含cgo,那么就可以做到window系統(tǒng)編譯linux的應用,如何做到的呢?Go引用了plan9的代碼,這就是不依賴系統(tǒng)的信息。Go語言這么多的優(yōu)勢,你還不想學嗎?我記得當時我看的是黑馬程序員的視頻,我對他們視頻的印象就是通俗易懂,就是好!

go程序如何分配堆棧的

在Go語言中有一些調試技巧能幫助我們快速找到問題,有時候你想盡可能多的記錄異常但仍覺得不夠,搞清楚堆棧的意義有助于定位Bug或者記錄更完整的信息。

本文將討論堆棧跟蹤信息以及如何在堆棧中識別函數所傳遞的參數。

Functions

先從這段代碼開始:

Listing 1

01 package main

02

03 func main() {

04 ? ? slice := make([]string, 2, 4)

05 ? ? Example(slice, "hello", 10)

06 }

07

08 func Example(slice []string, str string, i int) {

09 ? ? panic("Want stack trace")

10 }

Example函數定義了3個參數,1個string類型的slice, 1個string和1個integer, 并且拋出了panic,運行這段代碼可以看到這樣的結果:

Listing 2

Panic: Want stack trace

goroutine 1 [running]:

main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)

/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/

temp/main.go:9 +0x64

main.main()

/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/

temp/main.go:5 +0x85

goroutine 2 [runnable]:

runtime.forcegchelper()

/Users/bill/go/src/runtime/proc.go:90

runtime.goexit()

/Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1

goroutine 3 [runnable]:

runtime.bgsweep()

/Users/bill/go/src/runtime/mgc0.go:82

runtime.goexit()

/Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1

堆棧信息中顯示了在panic拋出這個時間所有的goroutines狀態(tài),發(fā)生的panic的goroutine會顯示在最上面。

Listing 3

01 goroutine 1 [running]:

02 main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)

/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/

temp/main.go:9 +0x64

03 main.main()

/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/

temp/main.go:5 +0x85

第1行顯示最先發(fā)出panic的是goroutine 1, 第二行顯示panic位于main.Example中, 并能定位到該行代碼,在本例中第9行引發(fā)了panic。

下面我們關注參數是如何傳遞的:

Listing 4

// Declaration

main.Example(slice []string, str string, i int)

// Call to Example by main.

slice := make([]string, 2, 4)

Example(slice, "hello", 10)

// Stack trace

main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)

這里展示了在main中帶參數調用Example函數時的堆棧信息,比較就能發(fā)現(xiàn)兩者的參數數量并不相同,Example定義了3個參數,堆棧中顯示了6個參數。現(xiàn)在的關鍵問題是我們要弄清楚它們是如何匹配的。

第1個參數是string類型的slice,我們知道在Go語言中slice是引用類型,即slice變量結構會包含三個部分:指針、長度(Lengthe)、容量(Capacity)

Listing 5

// Slice parameter value

slice := make([]string, 2, 4)

// Slice header values

Pointer: ?0x2080c3f50

Length: ? 0x2

Capacity: 0x4

// Declaration

main.Example(slice []string, str string, i int)

// Stack trace

main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)

因此,前面3個參數會匹配slice, 如下圖所示:

Figure 1

figure provided by Georgi Knox

我們現(xiàn)在來看第二個參數,它是string類型,string類型也是引用類型,它包括兩部分:指針、長度。

Listing 6

// String parameter value

"hello"

// String header values

Pointer: 0x425c0

Length: ?0x5

// Declaration

main.Example(slice []string,?str string, i int)

// Stack trace

main.Example(0x2080c3f50, 0x2, 0x4,?0x425c0, 0x5, 0xa)

可以確定,堆棧信息中第4、5兩個參數對應代碼中的string參數,如下圖所示:

Figure 2

figure provided by Georgi Knox

最后一個參數integer是single word值。

Listing 7

// Integer parameter value

10

// Integer value

Base 16: 0xa

// Declaration

main.Example(slice []string, str string,?i int)

// Stack trace

main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5,?0xa)

現(xiàn)在我們可以匹配代碼中的參數到堆棧信息了。

Figure 3

figure provided by Georgi Knox

Methods

如果我們將Example作為結構體的方法會怎么樣呢?

Listing 8

01 package main

02

03 import "fmt"

04

05 type trace struct{}

06

07 func main() {

08 ? ? slice := make([]string, 2, 4)

09

10 ? ? var t trace

11 ? ? t.Example(slice, "hello", 10)

12 }

13

14 func (t *trace) Example(slice []string, str string, i int) {

15 ? ? fmt.Printf("Receiver Address: %p\n", t)

16 ? ? panic("Want stack trace")

17 }

如上所示修改代碼,將Example定義為trace的方法,并通過trace的實例t來調用Example。

再次運行程序,會發(fā)現(xiàn)堆棧信息有一點不同:

Listing 9

Receiver Address:?0x1553a8

panic: Want stack trace

01 goroutine 1 [running]:

02 main.(*trace).Example(0x1553a8, 0x2081b7f50, 0x2, 0x4, 0xdc1d0, 0x5, 0xa)

/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/

temp/main.go:16 +0x116

03 main.main()

/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/

temp/main.go:11 +0xae

首先注意第2行的方法調用使用了pointer receiver,在package名字和方法名之間多出了"*trace"字樣。另外,參數列表的第1個參數標明了結構體(t)地址。我們從堆棧信息中看到了內部實現(xiàn)細節(jié)。

Packing

如果有多個參數可以填充到一個single word, 則這些參數值會合并打包:

Listing 10

01 package main

02

03 func main() {

04 ? ? Example(true, false, true, 25)

05 }

06?

07 func Example(b1, b2, b3 bool, i uint8) {

08 ? ? panic("Want stack trace")

09 }

這個例子修改Example函數為4個參數:3個bool型和1個八位無符號整型。bool值也是用8個bit表示,所以在32位和64位架構下,4個參數可以合并為一個single word。

Listing 11

01 goroutine 1 [running]:

02 main.Example(0x19010001)

/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/

temp/main.go:8 +0x64

03 main.main()

/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/

temp/main.go:4 +0x32

這是本例的堆棧信息,看下圖的具體分析:

Listing 12

// Parameter values

true, false, true, 25

// Word value

Bits ? ?Binary ? ? ?Hex ? Value

00-07 ? 0000 0001 ??01? ??true

08-15 ? 0000 0000 ??00? ? false

16-23 ? 0000 0001 ??01? ? true

24-31 ? 0001 1001 ??19? ? 25

// Declaration

main.Example(b1, b2, b3 bool, i uint8)

// Stack trace

main.Example(0x19010001)

以上展示了參數值是如何匹配到4個參數的。當我們看到堆棧信息中包括十六進制值,需要知道這些值是如何傳遞的。

【golang】內存逃逸常見情況和避免方式

因為如果變量的內存發(fā)生逃逸,它的生命周期就是不可知的,其會被分配到堆上,而堆上分配內存不能像棧一樣會自動釋放,為了解放程序員雙手,專注于業(yè)務的實現(xiàn),go實現(xiàn)了gc垃圾回收機制,但gc會影響程序運行性能,所以要盡量減少程序的gc操作。

1、在方法內把局部變量指針返回,被外部引用,其生命周期大于棧,則溢出。

2、發(fā)送指針或帶有指針的值到channel,因為編譯時候無法知道那個goroutine會在channel接受數據,編譯器無法知道什么時候釋放。

3、在一個切片上存儲指針或帶指針的值。比如[]*string,導致切片內容逃逸,其引用值一直在堆上。

4、因為切片的append導致超出容量,切片重新分配地址,切片背后的存儲基于運行時的數據進行擴充,就會在堆上分配。

5、在interface類型上調用方法,在Interface調用方法是動態(tài)調度的,只有在運行時才知道。

1、go語言的接口類型方法調用是動態(tài),因此不能在編譯階段確定,所有類型結構轉換成接口的過程會涉及到內存逃逸發(fā)生,在頻次訪問較高的函數盡量調用接口。

2、不要盲目使用變量指針作為參數,雖然減少了復制,但變量逃逸的開銷更大。

3、預先設定好slice長度,避免頻繁超出容量,重新分配。

當前標題:go語言內存分配方法,go語言內存占用
標題網址:http://chinadenli.net/article37/dsshppj.html

成都網站建設公司_創(chuàng)新互聯(lián),為您提供用戶體驗外貿建站ChatGPT企業(yè)網站制作移動網站建設網頁設計公司

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

成都網頁設計公司