你使用的Go版本是什么?
go version go1.11.4 windows/amd64
你做了什么?
https://play.golang.org/p/pbZJx5AZHpJ
你想看到什么?
hex.DecodeString
返回的字节切片有len == cap
个元素。
你看到了什么?
hex.DecodeString
返回的字节切片比严格必要的大小大一倍。
查看this rillig/pkglint commit了解我发现这个的实际例子。在一个commit message shortly before that中,我在堆转储中发现了奇怪的十六进制数字序列。
7条答案
按热度按时间6tdlim6h1#
我不确定使用较小的缓冲区(即使用较少的内存)是否值得所需的代码重复。在返回的切片(
return src[:n:n]
)中设置cap==len可能是值得的,尽管这会对任何向返回值追加内容的人造成性能损失。rggaifut2#
关于这个问题:
这里没有代码重复,但输出切片的大小与预期相符(对我来说)。
Go编译器应该足够聪明,能够判断在这种情况下
[]byte(s)
可以是一个无操作。使用此函数的后续用户可能已经使用了
Decode(dst, src)
。将内容追加到DecodeString
的结果似乎对我来说是一个边缘情况,至少在Go源代码树中我没有找到一个例子。因此,当我看到DecodeString
在输出预期完整的情况下浪费内存时,我感到很惊讶。kx1ctssn3#
Go编译器应该足够聪明,能够判断在这种情况下[]byte(s)可以是一个无操作。
我使用
runtime.ReadMemStats
来确认当我传入一个2048字节的字符串时,它会进行两次分配,总大小为3072字节,使用go version go1.11.4 darwin/amd64
。因此,至少在go1.11.4中,您的选项中的Go编译器不够智能。
avkwfej44#
@josharian 使用
src[:n:n]
修剪返回值并不能帮助垃圾回收器,因为它仍然没有释放字节数组的后半部分。我使用以下程序测试了这一点:js5cn81o5#
Go编译器应该足够聪明,能够判断在这种情况下[]byte(s)可以是一个无操作。但它不是。我为这个问题提交了#29810。
使用src[:n:n]修剪返回值并不能帮助垃圾回收。
确实如此。这样做唯一的好处是避免了这种问题的意外惊喜。@rillig也对“泄漏数据”表示担忧,但考虑到调用者已经有了十六进制输入,这对我来说并不是一个主要问题。总的来说,我认为我们不应该做出这个改变。
我使用runtime.ReadMemStats来确认。
顺便说一下,这种事情更容易通过基准测试来衡量。
vbkedwbf6#
一个附注:encoding/hex几乎毫无用处。Printf和它的朋友们在仔细管理内存的情况下可以很好地进行十六进制转换。
mwg9r5ms7#
另一个附带的评论:如果标准
encoding/*
包具有与strconv.Append*
语义相似的Append*(dst []byte, args...) []byte
方法,那就太好了。这样的方法可以很容易地在零分配模式下使用。有一个过时的关于encoding/base64
的提议在#19366。