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

(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.