【问题标题】:Does Go guarantee constant addresses?Go 是否保证地址不变?
【发布时间】:2014-03-05 11:05:38
【问题描述】:

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

uintptr(unsafe.Pointer(&obj))

无论何时调用,都将始终评估为相同的值?

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

如果您考虑像Mark-and-Compact 这样的垃圾收集策略,这很有趣。是否允许实现者使用这样的垃圾回收策略?

【问题讨论】:

    标签: go garbage-collection specifications


    【解决方案1】:

    没有这样的保证,完全可以实现移动收集器。

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

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

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

    【讨论】:

    • 那么 sync.copyChecker 中的代码利用了未定义的行为?将从 Go 分配的结构传递给 C 是否安全?指针算术需要多长时间才能避免与垃圾收集器竞争?
    • 1.是的,sync.copyChecker 正在使用未定义的行为。标准库的好处是它与编译器版本相关联,所以它是一个使用未定义行为的地方实际上不是问题。 2. 目前有效。从长远来看,我们还没有弄清楚我们要做什么。我更希望你在 Go 和 C 之间共享 C 指针,而不是共享 Go 指针。 3. 指针算术 - 转换为 uintptr,加/减,转换回 unsafe.Pointer - 应该在没有函数调用的单个语句中完成。我相信这不会中断。
    【解决方案2】:

    规范中没有任何内容可以保证这一点,可能是为了允许该语言的实现在未来使用压缩垃圾收集器。在this golang-nuts thread 中,一位开发人员建议如果将unsafe.Pointer 值固定在内存中,则可以进行压缩GC,但这不能扩展到所有unitptr 值。

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

    1. 如果obj 是零大小类型,则表达式的值可能不是唯一的,如described in the spec

    2. 在程序的生命周期中,特定的uintptr 值可能引用不同的对象。

    【讨论】:

    • 我确实回答了你的问题。 Go(语言)不保证它是不变的。
    • 好的。我已经加强了答案第一段的语言。规范中没有说明指针是固定的(仅关于如何比较它们),这似乎是一个深思熟虑的选择。
    • 也没有任何东西说他们没有被固定。可能隐含地假定了“固定指针”。
    • 如果语言规范假设指针是固定的,那么我链接到的邮件列表线程中的 Go 开发人员会这么说,而不是指出一些需要固定的有限情况。跨度>
    • 您链接到的讨论似乎只是一个假设场景。他们正在讨论何时必须固定指针以使对象看起来不会移动。从我收集的信息来看,他们建议在您使用 unsafe.Pointer 的那一刻,底层对象被固定并且在程序结束之前不会再移动。看起来与您从线程中为我读出的相反。
    【解决方案3】:

    没有绝对的保证。尤其是如果 Go 在其标记和清除垃圾收集器中添加压缩。

    存储在pointer types 和类型unsafe.Pointer 中的地址将在必要时由任何垃圾收集器更新。存储在uintptr 类型中作为无符号整数的地址不会被垃圾收集器更新。 uintptr 类型不是指针类型,它是整数类型。

    Numeric types

    uintptr 一个大到足以存储未解释的无符号整数 指针值的位

    converting unsafe.Pointers to uintptr

    指针应该保存在 unsafe.Pointers - 而不是 uintptrs - 总是。

    罗斯

    以你的为例,

    uintptr(unsafe.Pointer(&obj))
    

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

    【讨论】:

    • 据我所知,您链接到的讨论更关注垃圾收集器可能收集仅从 uintptr 引用的对象的问题。 Dave Cheney 甚至 said:“只要原始 unsafe.Pointer 值存在于堆栈帧中,就可以从 unsafe.Pointer 转换为 uintptr。”现在我更加困惑了。
    • 该线程中的修复似乎是代码持有 unintptr 并期望 GC 保持相关分配活动的情况。对于只考虑实际指针变量的精确 GC,情况并非如此。
    猜你喜欢
    • 2014-10-25
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    • 2013-04-30
    • 2017-09-02
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    相关资源
    最近更新 更多