Go保证固定地址吗?

Go保证固定地址吗?,go,garbage-collection,specifications,Go,Garbage Collection,Specifications,给定一个对象obj,是否保证 uintptr(unsafe.Pointer(&obj)) 无论何时调用,将始终计算为相同的值 当然,Go保证,如果将两个指针指向同一个对象,它们的比较总是相等的。不过,实现可能会移动内存中的对象,并透明地更新指向该对象的所有指针 这是有趣的,如果你考虑垃圾收集策略。是否允许实现者使用这样的垃圾收集策略?规范中没有任何东西可以保证这一点,可能是允许该语言的实现在将来使用压缩垃圾收集器。其中一位开发人员建议,如果不安全,压缩GC是可能的。指针值被固定在内存中

给定一个对象obj,是否保证

uintptr(unsafe.Pointer(&obj))
无论何时调用,将始终计算为相同的值

当然,Go保证,如果将两个指针指向同一个对象,它们的比较总是相等的。不过,实现可能会移动内存中的对象,并透明地更新指向该对象的所有指针


<>这是有趣的,如果你考虑垃圾收集策略。是否允许实现者使用这样的垃圾收集策略?

规范中没有任何东西可以保证这一点,可能是允许该语言的实现在将来使用压缩垃圾收集器。其中一位开发人员建议,如果
不安全,压缩GC是可能的。指针
值被固定在内存中,但这不能扩展到所有
unitptr

对于当前的Go运行时,我相信这是真的,但依赖它仍然是未定义的行为。不过,有几点需要注意:

  • 如果
    obj
    是零大小类型,则表达式的值可能不唯一,如下所示

  • 在程序的生命周期内,特定的
    uintptr
    值可能引用不同的对象


  • 没有绝对的保证。特别是如果Go将压缩添加到其标记和清理垃圾收集器中

    存储在s和type中的地址将在必要时由任何垃圾收集器更新。垃圾收集器不会更新以无符号整数形式存储在类型中的地址。
    uintpttr
    类型不是指针类型,而是整数类型

    uintpttr
    一个无符号整数,其大小足以存储未解释的 指针值的位

    指针应该保存在不安全的。指针-不是uintptrs- 总是

    罗斯

    以你为例,

    uintptr(unsafe.Pointer(&obj))
    

    您有一个无符号整数,而不是地址。

    没有这样的保证,因此可以实现移动收集器

    事实上,尽管垃圾收集器现在不移动堆对象,但在Go 1.3中,堆栈可以在需要增长时移动,因此完全有可能

    var obj int
    fmt.Println(uintptr(unsafe.Pointer(&obj)))
    bigFunc()
    fmt.Println(uintptr(unsafe.Pointer(&obj)))
    

    将打印两个不同的指针,因为bigFunc增加了堆栈,导致obj和堆栈上的所有其他对象移动。

    据我所知,您链接到的讨论更关注的问题是垃圾收集器可能会收集仅从uintptr引用的对象。Dave Cheney甚至说:“只要原始的unsafe.Pointer值存在于堆栈帧中,就可以从unsafe.Pointer转换为uintpttr。”现在我更困惑了。在该线程中,修复的情况似乎是代码持有
    unitptr
    ,并期望GC保持相关分配活动。对于只考虑实际指针变量的精确GC,情况并非如此。我确实回答了你的问题。Go(语言)不能保证它是恒定的。我加强了答案第一段的语言。规范中没有说明指针是固定的(只是关于如何比较指针),这似乎是一个深思熟虑的选择。也没有说明指针不是固定的。“固定指针”可能是隐式假定的。如果语言规范假定指针是固定的,那么我链接到的邮件列表线程中的Go开发人员可能会这样说,而不是指出一些需要固定的有限情况。您链接到的讨论似乎只是一个假设情况。他们正在讨论何时必须固定指针,使对象看起来不会移动。从我收集的信息来看,他们建议,当你使用一个不安全的.Pointer时,底层对象被固定,在程序结束之前不会再移动。看起来与我从线程中读到的相反。那么sync.copyChecker中的代码利用了未定义的行为?将分配的结构从Go传递到C安全吗?指针运算需要多长时间才能安全地与垃圾收集器竞争。是,sync.copyChecker正在使用未定义的行为。标准库的好处在于它与编译器版本相关联,因此它是一个使用未定义行为的地方,实际上不是问题。2.它现在起作用了。从长远来看,我们还没有弄清楚我们要做些什么。我更希望您在Go和C之间共享C指针,而不是共享Go指针。3.指针算术-转换为uintpttr、加/减、转换回unsafe.Pointer-应在单个语句中完成,无需函数调用。我相信这不会打破。