2 回答
TA贡献2041条经验 获得超4个赞
下面的代码没有做你认为的那样。
func ioutilHash() {
file, _ := ioutil.ReadFile(iso)
h := sha512.New()
fmt.Printf("%x", h.Sum(file))
}
这首先读取您的 1.5GB iso。正如 jnml 所指出的,它不断地制造越来越大的缓冲区来填充它。最后,总缓冲区大小不小于 1.5GB 且不大于 1.875GB(按当前实现)。
但是,在那之后,您再创建另一个缓冲区!h.Sum(file)不散列文件。它将当前哈希附加到文件中!这可能会也可能不会导致另一个分配。
真正的问题是您正在获取该文件,现在附加了散列,并用 %x 打印它。fmt 实际上是使用 jnml 指出的 ioutil.ReadAll 所使用的相同类型的方法进行预计算的。因此它不断分配越来越大的缓冲区来存储文件的十六进制。由于每个字母是 4 位,这意味着我们谈论的是不小于 3GB 的缓冲区,不大于 3.75GB。
这意味着您的活动缓冲区可能有 5.625GB 大。将其与 GC 不完美且未删除所有中间缓冲区相结合,它很容易填满您的空间。
编写该代码的正确方法是。
func ioutilHash() {
file, _ := ioutil.ReadFile(iso)
h := sha512.New()
h.Write(file)
fmt.Printf("%x", h.Sum(nil))
}
这几乎没有分配的数量。
底线是 ReadFile 很少是您想要使用的。IO 流(使用读取器和写入器)总是最好的选择。当你使用 io.Copy 时,你不仅分配的更少,而且你还同时散列和读取磁盘。在您的 ReadFile 示例中,这两个资源在彼此不依赖时同步使用。
TA贡献1805条经验 获得超9个赞
ioutil.ReadFile
工作正常。通过使用该功能来滥用系统资源来处理您知道很大的事情是您的错。
ioutil.ReadFile
是一个方便的文件帮助程序,您事先很确定它们会很小。像配置文件,大多数源代码文件等(实际上它正在优化文件 <= 1e9 bytes,但这是一个实现细节,而不是 API 合同的一部分。您的 1.5GB 文件强制它使用切片增长,从而分配超过在读取文件的过程中为您的数据提供一个大缓冲区。)
即使你使用的其他方法os.File
也不好。您绝对应该使用“bufio”包来顺序处理大文件,请参阅bufio.NewReader
。
- 2 回答
- 0 关注
- 230 浏览
添加回答
举报