曹大,关于string to slice 零拷贝的问题.希望解答一下.
今天看了煎鱼的文章:关于string to slice 零拷贝的问题
func string2bytes(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh := reflect.SliceHeader{
Data: stringHeader.Data,
Len: stringHeader.Len,
Cap: stringHeader.Len,
}
return *(*[]byte)(unsafe.Pointer(&bh))
}
查了一下上面的是值拷贝.Data是一个uintptr
.GC可能会回收它指向的内存地址.
为什么下面这种就不会出现Data指向的内存地址被回收呢?
func string2bytes1(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
var b []byte
pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
pbytes.Data = stringHeader.Data
pbytes.Len = stringHeader.Len
pbytes.Cap = stringHeader.Len
return b
}
是因为pbytes
的类型是指针类型*reflect.SliceHeader
,所以就不会出现上面的情况吗?GC移动Data
指向的内存后也会自动更新pbytes.Data
的值为新的内存地址吗?
我看到网上还有说uintptr
不能当零时变量使用.
如果我把有问题的代码改成下面这样.是不是也可以避免上述情况
func string2bytes(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh := &reflect.SliceHeader{
Data: stringHeader.Data,
Len: stringHeader.Len,
Cap: stringHeader.Len,
}
return *(*[]byte)(unsafe.Pointer(bh))
}
这里的bh是指针类型*reflect.SliceHeader
问题问的有点多.哈哈.还请见谅.????
43
收起
正在回答
2回答
我把上面的材料和相关的 issue 仔细读了一下,
理论上只要能分配出一个对象并引用那段内存就可以,如果从实现上来讲,你是 []byte 还是 sliceheader 都可以(但是一定要保证这个 header 是被分配出来的实例,不能只是转换过程中的字面量),只不过官方有这么个说法,如果你的 header 类型不对,可能不保证在 GC 期间不回收这段内存。
现在问的人太多,未来的版本在 unsafe 库里直接加 unsafe.Slice 和 unsafe.String 这两个类型了,不用 uintptr,直接用 unsafe.Pointer,不会再有之前讨论的问题:
所以我个人觉得这个问题意义不大 orz
Xargin
2021-05-31 16:10:37
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星