GO的環境配置? GOPATH GOROOT 都是幹嘛用的? 配置環境跟java對比有點奇怪 https://blog.csdn.net/weixin_40563757/article/details/115476327 語言特性 協程? 建立一個協程很簡單 加一個go關鍵字就可以 package ...
GO的環境配置?
GOPATH GOROOT 都是幹嘛用的?
配置環境跟java對比有點奇怪
https://blog.csdn.net/weixin_40563757/article/details/115476327
語言特性
協程?
建立一個協程很簡單 加一個go關鍵字就可以
package concurrence
import (
"fmt"
"time"
)
func hello(i int) {
println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
通過通信共用記憶體而不是通過共用記憶體而實現通信?
先提供一個或多個高性能隊列,線程/進程/微服務之間需要訪問別人時,不能直接讀寫別人的數據,而要通過隊列提出請求,然後在對方處理請求時再做相應處理。
Q&A
Q:我對java比較熟悉,java裡面通過鎖來實現共用記憶體,從而實現通信。 那啥叫”通過通信共用記憶體“啊?
A:ultimate go notebook 裡面講把channel當做信號收發,而不是一種數據結構。
Q:我可以理解成chenel在go里 就像 阻塞隊列BlockingQueu在java里嗎? 只不過chenel顆粒度更小實現的更加底層?
A:無人回覆。。。。
https://juejin.cn/post/7096859698984386574/#heading-14
Channel?
make(chan元素類型,[緩衝大小])·
- 無緩衝通道 make(chan int)
- 有緩衝通道 make(chan int,2)
例子:一個經典的生產消費模型
package concurrence
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
//複雜操作
println(i)
}
}
LOCK?
package concurrence
import (
"sync"
"time"
)
var (
x int64
lock sync.Mutex
)
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 2000; i++ {
x += 1
}
}
func Add() {
x = 0
for i := 0; i < 5; i++ {
go addWithoutLock()
}
time.Sleep(time.Second)
println("WithoutLock:", x)
x = 0
for i := 0; i < 5; i++ {
go addWithLock()
}
time.Sleep(time.Second)
println("WithLock:", x)
}
func ManyGoWait() {
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
記憶體管理
相關概念
-
Mutator:業務線程,分配新對象,修改對象指向關係
-
Collector: GC線程,找到存活對象,回收死亡對象的記憶體空間. Serial GC:只有一個collector
-
Parallel GC;:支持多個collectors同時回收的 GC演算法.
-
Concurrent GC: mutator(s)和collector(s)可以同時執行
Collectors必須感知對象指向關係的改變!
ConcurrentGC 的實現方式
- 三色標記
- 混合寫屏障
追蹤垃圾回收
可達性分析
-
對象被回收的條件:指針指向關係不可達的對象
-
標記根對象
靜態變數、全局變數、常量、線程棧等
-
標記:找到可達對象
求指針指向關係的傳遞閉包:從根對象出發,找到所有可達對象 -
清理:所有不可達對象
將存活對象複製到另外的記憶體空間(Copying GC)
將死亡對象的記憶體標記為句分配“(Mark-sweep GC)移動並整理存活對象(Mark-compact GC)
-
根據對象的生命周期,使用不同的標記和清理策略
引用計數
- 每個對象都有一個與之關聯的引用數目
- 對象存活的條件:當且僅當引用數大於0
- 優點:
記憶體管理的操作被平攤到程式執行過程中
記憶體管理不需要瞭解runtime的實現細節:C++智能指針(smart pointer) - 缺點:
維護引用計數的開銷較大:通過原子操作保證對引用計數操作的原子性和可見性 - 無法回收環形數據結構—— weak reference (swift 使用了 weal reference,相對解決了引用計數無法回收環形數據結構的問題)
記憶體開銷:每個對象都引入的額外記憶體空間存儲引用數目 - 回收記憶體時依然可能引發暫停
分塊
-
目標:為對象在heap 上分配記憶體·提前將記憶體分塊
-
調用系統調用mmap()向OS申請一大塊記憶體,例如4 MB·先將記憶體劃分成大塊,例如8KB,稱作mspan
再將大塊繼續劃分成特定大小的小塊,用於對象分配
noscan nspan:分配不包含指針的對象——GC不需要掃描
scan mspan:分配包含指針的對象—— GC需要掃描
-
對象分配:根據對象的大小,選擇最合適的塊返回
緩存
- TCMalloc: thread caching
- 每個p包含一個nrache用於快速分配,用於為綁定於p上的g分配對象
- mcache管理一組mspan
- 當mcache中的nspan分配完畢,向mcentral申請帶有未分配塊的mspan
- 當ms pan中沒有分配的對象,ns pan會被緩存在mcentral中,而不是立刻釋放並歸還給OS
記憶體管理優化
- 對象分配是非常高頻的操作:每秒分配GB級別的記憶體
- 小對象占比較高
- Go記憶體分配比較耗時
分配路徑長:g -> m->p -> mache -> ms pan -> memory block -> return pointer. - pprof:對象分配的函數是最頻繁調用的函數之一
Balanced GC(根據對象的生命周期,使用不同的標記和清理策略)
小對象的管理
- 每個g 都綁定一大塊記憶體(1KB),稱作 goroutine allocation buffer (GAB)·
- GAB用於noscan類型的小對象分配:<128 B
- 使用三個指針維護GAB: base, end, top
- Bump pointer(指針碰撞)風格對象分配
無須和其他分配請求互斥
分配動作簡單高效
大對象的管理
-
GAB對於Go記憶體管理來說是一個對象
-
本質:將多個小對象的分配合併成一次達對象的分配
-
問題:GAB的對象分配方式會導致記憶體被延遲釋放
-
方案:移動 GAB中存活的對象
當GAB總大小超過一定閾值時,將GAB中存活的對象複製到另外分配的GAB中
原先的 GAB可以釋放,避免記憶體泄漏
本質:用copying GC的演算法管理小對象