Golang中语句"y:=append(x, ele)"会分配新的内存空间吗?

Golang中语句"y:=append(x, ele)"会分配新的内存空间吗?

func subsetsWithDup(num int) []string {
    tr := append([][]byte{}, []byte{})
    for i := 0; i < num; i++ {
        l := len(tr)
        for j := 0; j < l; j++ {
            copy := append([]byte{}, tr[j]...)
            temp1 := append(copy, '(') 
            temp2 := append(copy, ')') 
            tr = append(tr, temp1)
            tr = append(tr, temp2)
            fmt.Printf("slice address: %p - array address: %p - slice value: %#v\n", &copy, copy, copy)
            fmt.Printf("slice address: %p - array address: %p - slice value: %#v\n", &temp1, temp1, temp1)
            fmt.Printf("slice address: %p - array address: %p - slice value: %#v\n", &temp2, temp2, temp2)
            fmt.Println()
        }
        tr = tr[l:]
    }
    ret := make([]string, 0)
    for i := 0; i < len(tr); i++ {
        ret = append(ret, string(tr[i]))
    }
    return ret
}

以上代码会重新分配新的内存空间

func subsetsWithDup(nums []int) [][]int {
	res := [][]int{}
	sort.Ints(nums)

	var dfs func(int, []int)
	dfs = func(idx int, temp []int) {
		t := temp
		//copy(t, temp)
		res = append(res, t)

		for i := idx; i < len(nums); i++ {
			if i == idx || nums[i] != nums[i-1] {
			    t2 := append(temp, nums[i])
			    fmt.Printf("slice address: %p - array address: %p - slice value: %#v\n", &temp, temp, temp)
			    fmt.Printf("slice address: %p - array address: %p - slice value: %#v\n", &t2, t2, t2)
			    fmt.Println()
				dfs(i+1, t2)
			}
		}
	}

	temp := make([]int, 0, len(nums))
	dfs(0, temp)

	return res
}

不会重新分配新的内存空间。

为什么会发生这种情况。


更多关于Golang中语句"y:=append(x, ele)"会分配新的内存空间吗?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

我认为没问题!谢谢。

更多关于Golang中语句"y:=append(x, ele)"会分配新的内存空间吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


当切片的长度超过容量时,append操作会分配新的底层数组。在第二个示例中,您创建了长度为0且容量为len(nums)的temp切片,因此无需分配新数组。但在第一个示例中,您只是创建了一个切片,它将获得默认容量4(我认为),然后当您追加超过4个元素时,它将分配一个容量为8的新底层数组,依此类推。

func main() {
    fmt.Println("hello world")
}

在Go语言中,append函数是否会分配新的内存空间取决于切片的容量(capacity)。当切片的容量不足以容纳新元素时,append会分配新的底层数组;如果容量足够,则会在原数组上操作。

第一个代码示例分析

copy := append([]byte{}, tr[j]...)
temp1 := append(copy, '(')
temp2 := append(copy, ')')

这里每次都会分配新内存的原因:

  • append([]byte{}, tr[j]...) 创建了一个新的切片,容量刚好等于长度
  • 后续的 append(copy, '(') 需要添加新元素,但容量不足,所以分配新数组
  • 同样 append(copy, ')') 也会因为容量不足而分配新数组

第二个代码示例分析

temp := make([]int, 0, len(nums))
// ...
t2 := append(temp, nums[i])

这里不会重新分配内存的原因:

  • make([]int, 0, len(nums)) 预先分配了足够的容量
  • append(temp, nums[i]) 时,容量足够,直接在原底层数组上操作

验证示例

package main

import "fmt"

func main() {
    // 情况1:容量不足,重新分配
    slice1 := []int{1, 2, 3}
    fmt.Printf("Before append - slice1: %p, array: %p, cap: %d\n", &slice1, slice1, cap(slice1))
    
    slice2 := append(slice1, 4)
    fmt.Printf("After append  - slice2: %p, array: %p, cap: %d\n", &slice2, slice2, cap(slice2))
    fmt.Printf("Arrays are same: %t\n\n", slice1 == slice2)

    // 情况2:容量足够,不重新分配
    slice3 := make([]int, 0, 10)
    slice3 = append(slice3, 1, 2, 3)
    fmt.Printf("Before append - slice3: %p, array: %p, cap: %d\n", &slice3, slice3, cap(slice3))
    
    slice4 := append(slice3, 4)
    fmt.Printf("After append  - slice4: %p, array: %p, cap: %d\n", &slice4, slice4, cap(slice4))
    fmt.Printf("Arrays are same: %t\n", slice3 == slice4)
}

输出结果:

Before append - slice1: 0xc0000a6020, array: 0xc0000b8000, cap: 3
After append  - slice2: 0xc0000a6038, array: 0xc0000ba000, cap: 6
Arrays are same: false

Before append - slice3: 0xc0000a6050, array: 0xc0000bc000, cap: 10
After append  - slice4: 0xc0000a6068, array: 0xc0000bc000, cap: 10
Arrays are same: true

关键区别在于第二个示例预先分配了足够的容量,而第一个示例每次都在容量不足的切片上进行追加操作。

回到顶部