亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么切片不斷從堆棧中逃脫?

為什么切片不斷從堆棧中逃脫?

Go
收到一只叮咚 2022-09-12 20:27:07
我正在嘗試解決leetcode問題排列。但是當我用-benchmem進行測試時,我發現它分配太多了,達到1957年的分配/操作時permute([]int{1,2,3,4,5,6})我發現它在生成子數字目標時逃逸到堆中。即使我試圖分配[6]int,并使用不安全的包來構建切片,它仍然.moved to heap我的問題是,為什么切片逃逸到堆,以及如何在堆棧上分配切片?這是我的代碼:package mainimport (    "fmt"    "reflect"    "unsafe")func permute(nums []int) [][]int {    resLen := 1    for i := 1; i<= len(nums);i ++{        resLen *= i    }    // pre allocate    res := make([][]int, resLen)    for i := range res{        res[i] = make([]int, 0, len(nums))    }    build(res, nums)    return res}func build(res [][]int,targets []int){    step := len(res) / len(targets)    for i := range targets{        for j := i*step; j < (i+1) * step; j ++{            res[j] = append(res[j], targets[i])        }        if len(targets) != 1{            var ab = [6]int{}            var buff []int            var bp  *reflect.SliceHeader            bp = (*reflect.SliceHeader)(unsafe.Pointer(&buff))            bp.Data = uintptr(unsafe.Pointer(&ab))            bp.Cap = 6            buff = append(buff, targets[:i]...)            buff = append(buff, targets[i+1:]...)            build(res[i*step:(i+1)*step], buff)        }    }    return}func main() {    nums := []int{1,2,3}    res := permute(nums)    fmt.Println(res)}build函數沒有不安全,但逃逸到堆:func build(res [][]int, targets []int) {    step := len(res) / len(targets)    for i := range targets {        for j := i * step; j < (i+1)*step; j++ {            res[j] = append(res[j], targets[i])        }        if len(targets) != 1 {            buff := make([]int, 0, 6) //  make([]int, 0, 6) escapes to heap            buff = append(buff, targets[:i]...)            buff = append(buff, targets[i+1:]...)            build(res[i*step:(i+1)*step], buff)        }    }    return}還有我的測試用例:package mainimport "testing"func Benchmark(b *testing.B){    for i:=0;i<b.N;i++{        permute([]int{1,2,3,4,5,6})    }}當我運行時,它報告go build -gcflags="-m"./main.go:32:8: moved to heap: ab
查看完整描述

1 回答

?
幕布斯6054654

TA貢獻1876條經驗 獲得超7個贊

嘗試使用顛覆編譯器只會使轉義分析更難完成其工作,從而阻止切片被堆棧分配。只需分配單個切片,并在每次循環迭代中重復使用它:unsafe.Pointer


func build(res [][]int, targets []int) {

    buff := make([]int, 0, 6)

    step := len(res) / len(targets)

    for i := range targets {

        buff = buff[:0]

        for j := i * step; j < (i+1)*step; j++ {

            res[j] = append(res[j], targets[i])

        }

        if len(targets) != 1 {

            buff = append(buff, targets[:i]...)

            buff = append(buff, targets[i+1:]...)

            build(res[i*step:(i+1)*step], buff)

        }

    }

    return

}

這可以通過編譯器正確優化


./main.go:26:17: make([]int, 0, 6) does not escape

并且只會導致所需的分配:


Benchmark-8  44607  26838 ns/op  52992 B/op  721 allocs/op


查看完整回答
反對 回復 2022-09-12
  • 1 回答
  • 0 關注
  • 122 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號