gpt4 book ai didi

string - 使用 reflect.StringHeader 将字节转换为字符串仍然分配新内存?

转载 作者:行者123 更新时间:2023-12-01 22:16:23 24 4
gpt4 key购买 nike

我有这个小代码片段来测试两种将字节 slice 转换为字符串对象的方法,一个分配新字符串对象的函数,另一个使用不安全指针算法构造字符串 *,它不分配新内存:

package main

import (
"fmt"
"reflect"
"unsafe"
)

func byteToString(b []byte) string {
return string(b)
}

func byteToStringNoAlloc(b []byte) string {
if len(b) == 0 {
return ""
}
sh := reflect.StringHeader{uintptr(unsafe.Pointer(&b[0])), len(b)}
return *(*string)(unsafe.Pointer(&sh))
}

func main() {
b := []byte("hello")
fmt.Printf("1st element of slice: %v\n", &b[0])

str := byteToString(b)
sh := (*reflect.StringHeader)(unsafe.Pointer(&str))
fmt.Printf("New alloc: %v\n", sh)

toStr := byteToStringNoAlloc(b)
shNoAlloc := (*reflect.StringHeader)(unsafe.Pointer(&toStr))
fmt.Printf("No alloc: %v\n", shNoAlloc) // why different from &b[0]
}

我在 go 1.13 下运行这个程序:
1st element of slice: 0xc000076068
New alloc: &{824634204304 5}
No alloc: &{824634204264 5}

我预计“slice 的第一个元素”应该打印出与“No alloc”相同的地址,但实际上它们非常不同。我哪里做错了?

最佳答案

首先,类型转换调用的是内部函数,在本例中是 slicebytetostring。
https://golang.org/src/runtime/string.go?h=slicebytetostring#L75

它将 slice 的内容复制到新分配的内存中。

在第二种情况下,您正在创建 slice 的新 header 并将其转换为字符串 header ,即 slice 内容的新非官方持有者。
这样做的问题是垃圾收集器不处理这种情况,并且生成的字符串标题将被标记为与保存实际内容的实际 slice 没有关系的单个结构,因此,您生成的字符串将仅有效而实际的内容持有者还活着(不要计算这个字符串标题本身)。
因此,一旦垃圾收集器清除了实际内容,您的字符串仍将指向相同的地址但已释放内存,如果您触摸它,您将收到 panic 错误或未定义的行为。

顺便说一句,不需要使用反射包及其头文件,因为直接转换已经创建了新的头文件:

*(*string)(unsafe.Pointer(&byte_slice))

关于string - 使用 reflect.StringHeader 将字节转换为字符串仍然分配新内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59807860/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com