Go version
Windows10/x86_64 Go1.22.5
Output of go env
in your module/workspace:
set GO111MODULE=on
set GOARCH=amd64
set GOBIN=C:\Users\User\go\bin
set GOCACHE=C:\Users\User\AppData\Local\go-build
set GOENV=C:\Users\User\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\User\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\User\go
set GOPRIVATE=
set GOPROXY=https://goproxy.cn,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.22.5
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=NUL
set GOWORK=
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\User\AppData\Local\Temp\go-build1301597658=/tmp/go-build -gno-record-gcc-switches
What did you do?
package main_test
import (
"encoding/json"
"fmt"
"reflect"
"testing"
)
func BenchmarkMain(b *testing.B) {
for i := 0; i < b.N; i++ {
jsonObj := struct {
Test1 string `json:"test1"`
Test2 string `json:"test2"`
Test3 string `json:"test3"`
Test4 string `json:"test4"`
}{
Test1: "test1",
Test2: "test2",
Test3: "test3",
Test4: "test4",
}
Used(json.Marshal(&jsonObj))
}
}
func Used(...any) {}
I also changed "encoding/json" to disable caching.
// Line:1269
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
func cachedTypeFields(t reflect.Type) structFields {
/*if f, ok := fieldCache.Load(t); ok {
return f.(structFields)
}
f, _ := fieldCache.LoadOrStore(t, typeFields(t))*/
return typeFields(t) //f.(structFields)
}
Normally func typeFields(t reflect.Type) structFields
has a loop that iterates over the Fields of the structure, but this requires memory allocation, and the structure I created has 4 Fields, but he only allocates memory 2 times for this operation, which is unrealistic!
What did you see happen?
D:\Desktop\OAC\jsontest>go test -benchmem -bench=^Benchmark -v -cpuprofile=cpu.pprof
goos: windows
goarch: amd64
pkg: jsontest
cpu: Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz
BenchmarkMain
BenchmarkMain-4 1899802 577.3 ns/op 144 B/op 2 allocs/op
PASS
ok jsontest 1.777s
What did you expect to see?
D:\Desktop\OAC\jsontest>go test -benchmem -bench=^Benchmark -v -cpuprofile=cpu.pprof
goos: windows
goarch: amd64
pkg: jsontest
cpu: Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz
BenchmarkMain
BenchmarkMain-4 1899802 577.3 ns/op 144 B/op 6 allocs/op
PASS
ok jsontest 1.777s
Comment From: gabyhelp
Related Issues and Documentation
- encoding/json: map[string]interface performance #35585 (closed)
- encoding/json: unmarshaling into struct is O(n^2) on number of struct fields #33073 (closed)
- encoding/binary: cache dataSize result across invocations of Read and Write for slice of structs #66253 (closed)
- encoding/json: adding a MarshalJSON method confuses JSON marshalling #67154 (closed)
- testing: Wrong number of allocations #54041 (closed)
- encoding/binary: more memory usage when encoding a slice of structs with smaller length. #66223 (closed)
- reflect: map iteration does unnecessary excessive allocation for non-pointer types #32424 (closed)
- encoding/json: marshaling RawMessage has poor performance #33422
- cmd/compile: fluent interfaces doing new allocations in go 1.19 #57434 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: seankhliao
I don't see why allocation needs to scale with the number of fields for marshaling, the only memory returned is the json byte slice.