go理論知識總結
基于const常量理解個中類型的內存分配引入參考
官方:Constant expressions may contain only constant operands and are evaluated at compile time.
Using constants can often be more efficient than using variables where possible because any references to the constant will be replaced at compile time使用常量通常比在可能的情況下使用變量更有效,因為對常量的任何引用都將在編譯時被替換;理解:如const A=7 m:=A 編譯后就直接是m:=7用數字替換完了自然沒有那個所謂A的地址
In many popular programming environments the stack usually refers to the call stack of a thread;A call stack is a LIFO stack data structure that stores arguments, local variables, and other data tracked as a thread executes functions
在許多流行的編程環境中,堆棧通常是指線程的調用堆棧
We must be able to safely free the memory of the most recent stack frame when it’s popped. We therefore can’t store anything on the stack that later needs to be referenced elsewhere.
Since threads are managed by the OS, the amount of memory available to a thread stack is typically fixed,e.g. a default of 8MB in many Linux environments。This means we also need to be mindful of how much data ends up on the stack, particularly in the case of deeply-nested recursive functions. If the stack pointer in the diagram above passes the stack guard, the program will crash with a stack overflow error.由于線程由操作系統管理,線程堆棧可用的內存量通常是固定的
The heap is a more complex area of memory . We can use the heap on demand to store data needed in our program. Memory allocated here can’t simply be freed when a function returns, and needs to be carefully managed to avoid leaks and fragmentation. 我們可以按需使用堆來存儲程序所需的數據,這里分配的內存不能簡單地在函數返回時釋放,需要小心管理以避免泄漏和碎片
The Go stack and heap
Threads managed by the OS are completely abstracted away from us by the Go runtime, and we instead work with a new abstraction: goroutines. Goroutines are conceptually very similar to threads, but they exist within user space. This means the runtime, and not the OS, sets the rules of how stacks behave。操作系統管理的線程被 Go 運行時完全抽象出來,我們使用一個新的抽象來工作:goroutines。 Goroutines 在概念上與線程非常相似,但它們存在于用戶空間中。 這意味著運行時而不是操作系統設置堆棧行為的規則
Rather than having hard limits set by the OS, goroutine stacks start with a small amount of memory (currently 2KB),Before each function call is executed, a check within the function prologue is executed to verify that a stack overflow won’t occur。This means that stacks in Go are dynamically sized, and can typically keep growing as long as there’s enough memory available to feed them。與操作系統設置硬限制不同,goroutine 堆棧以少量內存(當前為 2KB)開始,在執行每個函數調用之前,會執行函數序言中的檢查以驗證不會發生堆棧溢出,這意味著 Go 中的堆棧是動態大小的,并且只要有足夠的可用內存來喂它們,通常就可以保持增長
The Go heap。All goroutines share a common heap and anything that can’t be stored on the stack will end up there.所有 goroutine 共享一個公共堆,任何不能存儲在堆棧上的東西都將最終存儲在那里。
①線程-堆棧-內存
go數組和切片,參考https://go.dev/blog/slices-intro
Go’s arrays are values. An array variable denotes the entire array; it is not a pointer to the first array element (as would be the case in C).This means that when you assign or pass around an array value you will make a copy of its contents.而切片A slice is a descriptor of an array segment. It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment).

The length is the number of elements referred to by the slice. The capacity is the number of elements in the underlying array (beginning at the element referred to by the slice pointer). The distinction between length and capacity will be made clear as we walk through the next few examples.
As we slice s, observe the changes in the slice data structure and their relation to the underlying array:s = s[2:4]
Slicing does not copy the slice’s data. It creates a new slice value that points to the original array.
This makes slice operations as efficient as manipulating array indices.
Therefore, modifying the elements (not the slice itself) of a re-slice modifies the elements of the original slice:
關于切片引用數組導致整個數組不釋放問題
As mentioned earlier, re-slicing a slice doesn’t make a copy of the underlying array. The full array will be kept in memory until it is no longer referenced. Occasionally this can cause the program to hold all the data in memory when only a small piece of it is needed.
For example, this FindDigits function loads a file into memory and searches it for the first group of consecutive numeric digits, returning them as a new slice.
var digitRegexp = regexp.MustCompile("[0-9]+")
func FindDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
return digitRegexp.Find(b)
}
This code behaves as advertised, but the returned []byte points into an array containing the entire file. Since the slice references the original array, as long as the slice is kept around the garbage collector can’t release the array; the few useful bytes of the file keep the entire contents in memory.
To fix this problem one can copy the interesting data to a new slice before returning it:
func CopyDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
b = digitRegexp.Find(b)
c := make([]byte, len(b))
copy(c, b)
return c
}
A more concise version of this function could be constructed by using append. This is left as an exercise for the reader.

Slicing does not copy the slice’s data. It creates a new slice value that points to the original array.
浙公網安備 33010602011771號