没有内存泄漏,this 证明了这一点。
但是有一个issue:在func Fprint(w io.Writer, a ...interface{}) (n int, err error) 中对p := newPrinter() 的调用在此处初始化p.fmt.init(&p.buf) 返回空闲内存(切片的底层数组)而不将其初始化为零(可能出于性能原因未初始化 - 我们预计会全部为零)。
TL;DR:
两种解决方案:
1. 解决方法:使用s.w.Write(p) 而不是s.w.Write(p[:64]),或者编辑您的代码并将p[len(p):cap(p)] 全部设置为零(如果您不使用或无法使用第二种解决方案):
func (s *SecWriter) Write(p []byte) (n int, err error) {
b := p[len(p):cap(p)]
for i := range b {
b[i] = 0
}
fmt.Println(string(p), len(p), cap(p))
// here
tmp := fmt.Sprintln("info{SSSSSSSSSSSSSSSSSSSSSSSSSSS}")
if tmp == "" {
}
s.w.Write(p[:64])
return 64, nil
}
- 在 Windows (
C:\Go\src\fmt\format.go) 或 Linux (/usr/local/go/src/fmt/format.go) 文件的第 58 行将缓冲区设置为全零:
b := (*buf)[:cap(*buf)]
for i := range b {
b[i] = 0
}
这个函数内部:
func (f *fmt) init(buf *buffer) {
b := (*buf)[:cap(*buf)]
for i := range b {
b[i] = 0
}
f.buf = buf
f.clearflags()
}
您的代码输出与此应用:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 64 64
1 1 128
buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1
长答案:
您正在观看超出指定长度的切片数据,并且您可以看到切片数据到切片容量。
您可以将:m.Writer.Write(p[:8]) 替换为:m.Writer.Write(p),这会使您的代码正常工作。以下代码显示template.Parse() 将模板标记为3 个部分,并调用my.Write() 3 次。这里有趣的部分是对my.Write() 的第二次 调用显示了一个编译器生成的具有不同切片容量的切片,该切片容量未初始化为零,“也许这是一个小无害issue”:
如果你想窥探你电脑的内存,试试this:
package main
import (
"bytes"
"fmt"
"io"
"text/template"
)
func main() {
buf := &bytes.Buffer{}
my := &myWriter{"You", buf}
template.Must(template.New("my").Parse("Hi{{.Name}}Bye.")).Execute(my, my)
fmt.Printf("<<%q>>\n", buf.String())
}
func (m *myWriter) Write(p []byte) (n int, err error) {
fmt.Printf("len=%v cap=%v\t%v %v\n", len(p), cap(p), string(p), p[:cap(p)])
no++
fmt.Println("gen:", no, gen())
m.Writer.Write(p)
// m.Writer.Write(p[:8])
return 8, nil
}
type myWriter struct {
Name string
io.Writer
}
const genLen = 8
func gen() string {
b := [genLen]byte{}
for i := range b {
b[i] = no
}
return string(b[:])
}
var no = byte(49) //'1'
输出:
len=2 cap=8 Hi [72 105 0 0 0 0 0 0]
gen: 50 22222222
len=3 cap=64 You [89 111 117 58 32 53 48 32 50 50 50 50 50 50 50 50 10 50 32 49 48 53 32 48 32 48 32 48 32 48 32 48 32 48 93 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
gen: 51 33333333
len=4 cap=8 Bye. [66 121 101 46 0 0 0 0]
gen: 52 44444444
<<"HiYouBye.">>
然后改const genLen = 64试试this
有趣:cap=64 更改为 cap=128(这不是预期的):
输出:
len=2 cap=8 Hi [72 105 0 0 0 0 0 0]
gen: 50 2222222222222222222222222222222222222222222222222222222222222222
len=3 cap=128 You [89 111 117 58 32 53 48 32 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 50 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
gen: 51 3333333333333333333333333333333333333333333333333333333333333333
len=4 cap=8 Bye. [66 121 101 46 0 0 0 0]
gen: 52 4444444444444444444444444444444444444444444444444444444444444444
<<"HiYouBye.">>
t.Execute(my, my) 调用func (m *myWriter) Write(p []byte),所以p 与len=3 和cap=128 由模板引擎生成。
在第 230 行调试 /usr/local/go/src/fmt/print.go 文件中的第二个代码后,它似乎是 fmt.buffer 和 length=3 和 cap=128,这里:
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrint(a)
n, err = w.Write(p.buf)
p.free()
return
}
对p := newPrinter()的调用在这里初始化p.fmt.init(&p.buf):
// newPrinter allocates a new pp struct or grabs a cached one.
func newPrinter() *pp {
p := ppFree.Get().(*pp)
p.panicking = false
p.erroring = false
p.wrapErrs = false
p.fmt.init(&p.buf)
return p
}
获取并返回空闲内存而不将其初始化为零。