曹大,关于string to slice 零拷贝的问题.希望解答一下.

曹大,关于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

问题问的有点多.哈哈.还请见谅.????

正在回答

登陆购买课程后可参与讨论,去登陆

2回答

我把上面的材料和相关的 issue 仔细读了一下,


理论上只要能分配出一个对象并引用那段内存就可以,如果从实现上来讲,你是 []byte 还是 sliceheader 都可以(但是一定要保证这个 header 是被分配出来的实例,不能只是转换过程中的字面量),只不过官方有这么个说法,如果你的 header 类型不对,可能不保证在 GC 期间不回收这段内存。


现在问的人太多,未来的版本在 unsafe 库里直接加 unsafe.Slice 和 unsafe.String 这两个类型了,不用 uintptr,直接用 unsafe.Pointer,不会再有之前讨论的问题:


https://github.com/golang/go/blob/fadad851a3222867b374e901ede9c4919594837f/src/cmd/vendor/golang.org/x/sys/internal/unsafeheader/unsafeheader.go#L19


所以我个人觉得这个问题意义不大 orz

  • 猫粮s 提问者 #1

    辛苦曹大了

    2021-05-31 17:07:04
Xargin 2021-05-31 16:10:37

这篇文章看起来是从这个 issue 发挥出来的吧: https://github.com/golang/go/issues/25484


不懂瞎 hack 的人挺多的,某些大厂员工也是

问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师