Существует нет утечки памяти , , это подтверждает это.
Но есть проблема : вызов p := newPrinter()
инициализирован здесь p.fmt.init(&p.buf)
in func Fprint(w io.Writer, a ...interface{}) (n int, err error)
возвращает свободную память (базовый массив среза), не инициализируя ее нулем (что, вероятно, не инициализировано по соображениям производительности - , который мы ожидали равным нулю ).
TL; DR:
Два решения:
1. Обходной путь: используйте s.w.Write(p)
вместо s.w.Write(p[:64])
или измените код и установите p[len(p):cap(p)]
все в ноль (если вы не можете или не можете коснуться2-е решение):
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()
три раза. интересная часть здесь - это второй вызов my.Write()
, показывающий сгенерированный компилятором срез с различной емкостью среза, который не инициализирован на ноль, «возможно, это незначительная безвредная проблема ":
Если вы хотите шпионить за памятью вашего компьютера, попробуйте 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
try this intersting : 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
, сгенерированным механизмом тамплат.
После отладки 2-го кода внутри файла /usr/local/go/src/fmt/print.go
в строке 230кажется, это 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
}
Получает и возвращает свободную память без инициализации ее нуля.