首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在sync.Pool中重用片?

如何在sync.Pool中重用片?
EN

Stack Overflow用户
提问于 2022-07-07 06:19:57
回答 1查看 684关注 0票数 2

请考虑以下代码:

代码语言:javascript
复制
type TestStruct struct {
    Name string
}

func TestSliceWithPool(t *testing.T) {
    var slicePool = sync.Pool{
        New: func() interface{} {
            t.Log("i am created")
            s := make([]interface{}, 0)
            return s
        },
    }

    s, _ := slicePool.Get().([]interface{})
    t.Logf("Lenth: %d, Cap: %d, Pointer: %p", len(s), cap(s), s)
    for i := 0; i < 9000; i++ {
        st := &TestStruct{Name: "test"}
        s = append(s, st)
    }
    for _, v := range s {
        if value, ok := v.(TestStruct); ok {
            if value.Name != "test" {
                t.Error("u are changed!")
            }
        }
    }
    s = s[:0]
    slicePool.Put(s)

    s2, _ := slicePool.Get().([]interface{})
    t.Logf("Lenth: %d, Cap: %d, Pointer: %p", len(s), cap(s), s)
    for i := 0; i < 8000; i++ {
        st := &TestStruct{Name: "test2"}
        s2 = append(s2, st)
    }
    for _, v := range s2 {
        if value, ok := v.(TestStruct); ok {
            if value.Name != "test2" {
                t.Error("u are changed!")
            }
        }
    }
    slicePool.Put(s2)
}

测试结果如下:

代码语言:javascript
复制
slice_test.go:63: i am created
slice_test.go:70: Lenth: 0, Cap: 0, Pointer: 0x1019598
slice_test.go:86: Lenth: 0, Cap: 9728, Pointer: 0xc000500000

为什么它只生成一次,但地址是不同的?为什么上限是9728?像这样用同一片有什么问题吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-07 06:46:50

为什么只生成一次,但地址不同?

因为在第一个for循环中,您将超出其容量(在New中设置为零)附加到它,并将append的结果重新分配给它。详细信息:Why does append() modify the provided slice? (See example)

,当我像这样使用相同的切片时,有什么问题吗?

可能会有。当您使用s重新设置s = s[:0]时,您正在重置长度,而不是容量。支持数组仍然与上一次追加和重新分配操作相同。

因此,如果再次添加到s2中,容量将不足以导致重新分配,最终将覆盖支持数组的第一个元素:

一个示范的例子:

代码语言:javascript
复制
func TestSliceWithPool(t *testing.T) {
    var slicePool = sync.Pool{
        New: func() interface{} {
            t.Log("Created")
            s := make([]interface{}, 0)
            return s
        },
    }

    s, _ := slicePool.Get().([]interface{})
    for i := 0; i < 10; i++ {
        s = append(s, i)
    }
    fmt.Println(s) 
    // ^ output: [0 1 2 3 4 5 6 7 8 9]

    s = s[:0]
    slicePool.Put(s)

    s2, _ := slicePool.Get().([]interface{})
    fmt.Println(s)
    // ^ output: []

    for i := 0; i < 5; i++ {
        s2 = append(s2, i*10)
    }
    fmt.Println(s2) 
    // ^ output: [0 10 20 30 40]

    fmt.Println(s2[:10])
    // ^ output: [0 10 20 30 40 5 6 7 8 9]
}

这可能是可以的,因为您现在有一个扩展容量不需要追加重新分配的片,但如果您的应用程序保持指向相同支持数组的其他片头(如ss2),则也可能是内存泄漏,从而防止缓冲区的垃圾收集。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72893095

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档