Igu*_*han 1 garbage-collection go
string到[]byte\xef\xbc\x9afunc unsafeStringToBytes(xxxxxs string) []byte {\n p := &xxxxxs\n sh := (*reflect.StringHeader)(unsafe.Pointer(p))\n sliceHeader := &reflect.SliceHeader{\n Data: sh.Data,\n Len: sh.Len,\n Cap: sh.Len,\n }\n\n runtime.GC()\n time.Sleep(10 * time.Nanosecond)\n\n b := *(*[]byte)(unsafe.Pointer(sliceHeader))\n return b\n}\nRun Code Online (Sandbox Code Playgroud)\npackage gc\n\nimport (\n "bufio"\n "log"\n "os"\n "reflect"\n "runtime"\n "testing"\n "time"\n "unsafe"\n)\n\nfunc TestWriteLog(t *testing.T) {\n f1, err := os.Create("./log")\n if err != nil {\n log.Fatal(err)\n }\n defer f1.Close()\n\n for i := 0; i <= 1000000; i++ {\n _, err := f1.WriteString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\\n")\n if err != nil {\n t.Fatal(err)\n }\n }\n}\n\nfunc heapHeapHeap() {\n var a *[]byte\n for {\n tmp := make([]byte, 100000000, 100000000)\n a = &tmp\n _ = a\n }\n}\n\nfunc TestStringToBytes(t *testing.T) {\n go heapHeapHeap()\n\n f1, err := os.Open("./log")\n if err != nil {\n log.Fatal(err)\n }\n defer f1.Close()\n\n reader := bufio.NewReader(f1)\n count := 1\n var firstChar byte\n\n for {\n s, _ := reader.ReadString(\'\\n\')\n if len(s) == 0 {\n continue\n }\n firstChar = s[0]\n\n // HERE BE DRAGONS\n bytes2 := unsafeStringToBytes(s)\n\n _, _ = reader.ReadString(\'\\n\')\n\n if len(bytes2) > 0 && firstChar != bytes2[0] {\n t.Fatalf("win! after %d iterations\\n", count)\n os.Exit(0)\n }\n\n count++\n //t.Log(count)\n }\n}\n\nfunc unsafeStringToBytes(xxxxxs string) []byte {\n p := &xxxxxs\n sh := (*reflect.StringHeader)(unsafe.Pointer(p))\n sliceHeader := &reflect.SliceHeader{\n Data: sh.Data,\n Len: sh.Len,\n Cap: sh.Len,\n }\n\n runtime.GC()\n time.Sleep(10 * time.Nanosecond)\n\n b := *(*[]byte)(unsafe.Pointer(sliceHeader))\n //runtime.KeepAlive(xxxxxs)\n return b\n}\nRun Code Online (Sandbox Code Playgroud)\n首先,运行TestWriteLog生成log文件。然后我们运行TestStringToBytes:
$ go test -gcflags=\'-m\' -v -run TestStringToBytes 1 \xe2\x86\xb5\n# go_test/gc [go_test/gc.test]\n./string2bytes_test.go:15:22: inlining call to os.Create\n./string2bytes_test.go:29:6: can inline heapHeapHeap\n./string2bytes_test.go:41:20: inlining call to os.Open\n./string2bytes_test.go:47:27: inlining call to bufio.NewReader\n./string2bytes_test.go:47:27: inlining call to bufio.NewReaderSize\n./string2bytes_test.go:47:27: inlining call to bufio.(*Reader).reset\n./string2bytes_test.go:14:19: leaking param: t\n./string2bytes_test.go:17:12: ... argument does not escape\n./string2bytes_test.go:24:11: ... argument does not escape\n./string2bytes_test.go:32:3: moved to heap: tmp\n./string2bytes_test.go:32:14: make([]byte, 100000000, 100000000) escapes to heap\n./string2bytes_test.go:73:26: xxxxxs does not escape\n./string2bytes_test.go:76:17: &reflect.SliceHeader{...} does not escape\n./string2bytes_test.go:38:24: leaking param: t\n./string2bytes_test.go:43:12: ... argument does not escape\n./string2bytes_test.go:47:27: new(bufio.Reader) does not escape\n./string2bytes_test.go:47:27: make([]byte, bufio.size) escapes to heap\n./string2bytes_test.go:64:12: ... argument does not escape\n./string2bytes_test.go:64:13: count escapes to heap\n./string2bytes_test.go:90:24: leaking param: s\n# go_test/gc.test\n/var/folders/6w/7dl1f7mx2pv1_v48_mg37br80000gn/T/go-build1924552004/b001/_testmain.go:39:6: can inline init.0\n/var/folders/6w/7dl1f7mx2pv1_v48_mg37br80000gn/T/go-build1924552004/b001/_testmain.go:47:24: inlining call to testing.MainStart\n/var/folders/6w/7dl1f7mx2pv1_v48_mg37br80000gn/T/go-build1924552004/b001/_testmain.go:47:42: testdeps.TestDeps{} escapes to heap\n/var/folders/6w/7dl1f7mx2pv1_v48_mg37br80000gn/T/go-build1924552004/b001/_testmain.go:47:24: &testing.M{...} escapes to heap\n=== RUN TestStringToBytes\n string2bytes_test.go:64: win! after 164307 iterations\n--- FAIL: TestStringToBytes (57.46s)\nFAIL\nexit status 1\nFAIL go_test/gc 57.938s\nRun Code Online (Sandbox Code Playgroud)\n结果显示,它失败了。
\nxxxxxs被GC了,因为当我把它放在runtime.KeepAlive(xxxxxs)函数中时,失败就再也没有出现过。func unsafeStringToBytes(xxxxxs string) []byte {\n p := &xxxxxs\n sh := (*reflect.StringHeader)(unsafe.Pointer(p))\n sliceHeader := &reflect.SliceHeader{\n Data: sh.Data,\n Len: sh.Len,\n Cap: sh.Len,\n }\n\n runtime.GC()\n time.Sleep(10 * time.Nanosecond)\n\n b := *(*[]byte)(unsafe.Pointer(sliceHeader))\n runtime.KeepAlive(xxxxxs)\n return b\n}\nRun Code Online (Sandbox Code Playgroud)\n./string2bytes_test.go:73:26: xxxxxs does not escape\nRun Code Online (Sandbox Code Playgroud)\n没有xxxxxs逃逸,它位于go栈中,怎么可能被GC!
谁能告诉我为什么?解决方案“ xxxxxsbe GC”是错误的吗?还是有其他原因?
您的代码违反了unsafe.Pointer 规则。特别是,规则 6 指定不应声明或分配 的变量reflect.SliceHeader。
因此,当 GC 增大/缩小/移动堆栈时,GC 可能会失去对字符串的跟踪。
请注意,在现代 Go 版本中,有一种更简单、更安全的方法来进行您想要的转换:unsafe.Slice(unsafe.StringData(s), len(s)).