New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
非类型安全指针-使用模式六中对于KeepAlive的一个疑问 #27
Comments
这个是肯定的,见 https://gfw.go101.org/article/summaries.html#compile-time-evaluation 我重新仔细考虑了一下这个例子,感觉此处的 你觉得呢? 其实 |
这块比较微妙,如果编译器不能保证 |
多谢回复。理解你在原文中表达的意思了。 赋值之后, 通过命令 hdr.Data = tmpPtr 才会有 如果我没理解错的话, 原始文件写在同一行 0x00d4 00212 (main.go:14) TESTB AL, (DI)
0x00d6 00214 (main.go:14) PCDATA $2, $4
0x00d6 00214 (main.go:14) MOVQ "".&a+168(SP), AX
0x00de 00222 (main.go:14) PCDATA $2, $-2
0x00de 00222 (main.go:14) PCDATA $0, $-2
0x00de 00222 (main.go:14) CMPL runtime.writeBarrier(SB), $0
0x00e5 00229 (main.go:14) JEQ 236
0x00e7 00231 (main.go:14) JMP 1245
0x00ec 00236 (main.go:14) MOVQ AX, "".bs+352(SP)
0x00f4 00244 (main.go:14) JMP 246
0x00f6 00246 (main.go:15) PCDATA $2, $1
0x00f6 00246 (main.go:15) PCDATA $0, $5
0x00f6 00246 (main.go:15) MOVQ "".&a+168(SP), AX
0x00fe 00254 (main.go:15) PCDATA $0, $6
0x00fe 00254 (main.go:15) MOVQ AX, ""..autotmp_28+112(SP)
0x0103 00259 (main.go:15) PCDATA $2, $0
0x0103 00259 (main.go:15) MOVQ AX, ""..autotmp_14+160(SP) 修改后的源文件 package main
import (
"fmt"
"unsafe"
"reflect"
"runtime"
)
func main() {
a := [6]byte{'G', 'o', '1', '0', '1'}
bs := []byte("Golang")
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&bs))
tmpPtr := uintptr(unsafe.Pointer(&a))
hdr.Data = tmpPtr
runtime.KeepAlive(&a) // 必不可少!
hdr.Len = 2
hdr.Cap = len(a)
fmt.Printf("%s\n", bs) // Go
bs = bs[:cap(bs)]
fmt.Printf("%s\n", bs) // Go101
} 写在不同行 0x00ba 00186 (main.go:14) PCDATA $2, $1
0x00ba 00186 (main.go:14) LEAQ "".a+82(SP), AX
0x00bf 00191 (main.go:14) PCDATA $2, $0
0x00bf 00191 (main.go:14) MOVQ AX, "".tmpPtr+88(SP)
0x00c4 00196 (main.go:15) PCDATA $2, $4
0x00c4 00196 (main.go:15) MOVQ "".hdr+120(SP), DI
0x00c9 00201 (main.go:15) TESTB AL, (DI)
0x00cb 00203 (main.go:15) PCDATA $2, $-2
0x00cb 00203 (main.go:15) PCDATA $0, $-2
0x00cb 00203 (main.go:15) CMPL runtime.writeBarrier(SB), $0
0x00d2 00210 (main.go:15) JEQ 217
0x00d4 00212 (main.go:15) JMP 1216
0x00d9 00217 (main.go:15) MOVQ AX, (DI)
0x00dc 00220 (main.go:15) JMP 222 |
感觉这个和writeBarrier的关系并不太大。writeBarrier主要是在垃圾回收执行过程对指针赋值做出的特殊处理,以防止误把仍在使用的内存标记为垃圾。 Go核心团队成员曾说过:为了避免垃圾回收算法的复杂性,目前官方编译器保证指针的赋值都是原子操作,而并未对其它赋值做出这个保证。这样垃圾回收器不会在一个指针赋值的执行撕裂成两部分,但对于其它赋值,是有可能被撕裂成两部分的,比如上面提到的 |
这里“垃圾回收器不会在一个指针赋值的执行撕裂成两部分”,确切地指在垃圾回收器的扫描过程不会运行在一个指针赋值的执行之间,而只能完全运行于此指针赋值的执行之前或者之后。 |
我在Windows平台下使用 package main
import (
"fmt"
"unsafe"
"reflect"
// "runtime"
)
func main() {
a := [6]byte{'G', 'o', '1', '0', '1'}
bs := []byte("Golang")
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&bs))
hdr.Data = uintptr(unsafe.Pointer(&a))
// runtime.KeepAlive(&a) // 必不可少!
hdr.Len = 2
hdr.Cap = len(a)
fmt.Printf("%s\n", bs) // Go
bs = bs[:cap(bs)]
fmt.Printf("%s\n", bs) // Go101
} .\main.go:14:36: &a escapes to heap
.\main.go:11:2: moved to heap: a
.\main.go:18:12: io.Writer(os.Stdout) escapes to heap
.\main.go:18:13: bs escapes to heap
.\main.go:12:14: ([]byte)("Golang") escapes to heap
.\main.go:20:12: io.Writer(os.Stdout) escapes to heap
.\main.go:20:13: bs escapes to heap
.\main.go:13:47: main &bs does not escape
.\main.go:18:12: main []interface {} literal does not escape
.\main.go:20:12: main []interface {} literal does not escape
<autogenerated>:1: os.(*File).close .this does not escape
<autogenerated>:1: os.(*File).isdir .this does not escape 基于上面的讨论,此处的 多谢耐心解答。 |
看来 这个和 一个 |
你好,关于非类型安全指针一文中的使用模式六,有个疑问,前来请教。
这里对于
a
被回收的原因有些疑问,因为后面hdr.Cap = len(a)
有引用到a
,为何a
仍然可能会被回收呢?难道说是因为len(a)
操作在编译期变成了常量6,导致没有对a
产生引用?The text was updated successfully, but these errors were encountered: