What happens to pointer to element when Go moves slice to another place in memory?

huangapple go评论87阅读模式
英文:

What happens to pointer to element when Go moves slice to another place in memory?

问题

我有以下代码:

package main

import "fmt"

func main() {
    a := []int{1}
    b := &a[0]
    fmt.Println(a, &a[0], b, *b) // 输出 [1] 0xc00001c030 0xc00001c030 1

    a = append(a, 1, 2, 3)
    fmt.Println(a, &a[0], b, *b) // 输出 [1 1 2 3] 0xc000100020 0xc00001c030 1
}

首先,它创建了一个包含1个int的切片。它的长度为1,容量也为1。然后,我获取其第一个元素的指针,并在打印中获取其底层指针值。正如预期的那样,它正常工作。

然后,我向切片添加了3个元素,使得切片的容量增加,从而将其复制到内存中的另一个位置。之后,我打印了切片的第一个元素的地址(通过获取指针),该地址与b中存储的地址不同。

然而,当我打印b的底层值时,它也正常工作。我不明白为什么它能正常工作。据我所知,指向b的第一个元素的切片被复制到内存中的另一个位置,因此它的先前内存必须已被释放。然而,它似乎仍然存在。

如果我们看一下映射,Golang甚至不允许我们通过键创建元素的指针,因为存在完全相同的问题-底层数据可能被移动到内存中的另一个位置。然而,对于切片来说,它完全正常工作。为什么会这样?它是如何工作的?内存没有被释放,是因为仍然有一个指向该内存的变量吗?它与映射有何不同?

英文:

I have the following code

package main

import "fmt"

func main() {
	a := []int{1}
	b := &a[0]
	fmt.Println(a, &a[0], b, *b) // prints [1] 0xc00001c030 0xc00001c030 1

	a = append(a, 1, 2, 3)
	fmt.Println(a, &a[0], b, *b) // prints [1 1 2 3] 0xc000100020 0xc00001c030 1
}

First it creates a slice of 1 int. Its len is 1 and cap is also 1. Then I take a pointer to its first element and get the underlying pointer value in print. It works fine, as expected.

Than I add 3 more elements to the slice making go expand the capacity of the slice, thus copying it to another place in memory. After that I print the address (by taking a pointer) of the slice's first element which is now different from address stored in b.

However, when I then print the underlying value of b it also works fine. I don't understand why does it work. As far as I know the slice to which first element b points to was copied to another place in memory, so its previous memory must have been released. However, it seems to still be there.

If we look on maps, golang doesn't even allow us to create pointers on element by key because of the exact same problem - underlying data can be moved to another place in memory. However, it works perfectly fine with slices. Why is it so? How does it really works? Is the memory not being freed because there still is a variable which points to this memory? How is it different from maps?

答案1

得分: 6

当Go将切片移动到内存中的另一个位置时,指向元素的指针会发生什么情况?

没有任何变化。

当我打印b的底层值时,它也能正常工作。我不明白为什么会这样。

为什么它不能正常工作呢?

原始指向的内存位置仍然存在,没有改变。只要有任何东西(比如b)仍然引用它,它就可以继续使用。一旦所有对该内存的引用都被移除(即超出作用域),垃圾回收器可能会允许其他东西使用它。

英文:

> What happens to pointer to element when Go moves slice to another place in memory?

Nothing.

> [W]hen I then print the underlying value of b it also works fine. I don't understand why does it work.

Why wouldn't it work?

The memory location originally pointed to is still there, unaltered. And as long as anything (such as b) still references it, it will remain usable. Once all references to that memory are removed (i.e. go out of scope), then the garbage collector may allow it to be used by something else.

答案2

得分: 1

当Go将切片移动到内存的另一个位置时,指向元素的指针会发生什么变化?

我相信当前的GC实现根本不会移动这样的对象,尽管规范允许这样做。除非你使用"unsafe"包,否则即使它移动了底层数据结构,你也不太可能遇到任何问题。

英文:

> What happens to pointer to element when Go moves slice to another
> place in memory?

I believe the current GC implementation do not move such objects at all, although the specifications allow for this to happen. Unless you use the "unsafe" package, you are unlikely to encounter any problems even if it did move the underlying data structure.

huangapple
  • 本文由 发表于 2022年12月12日 18:53:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/74770014.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定