aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <m.shulhan@gmail.com>2024-01-25 04:23:24 +0700
committerShulhan <m.shulhan@gmail.com>2026-04-14 21:51:40 +0700
commit779b2c6eaca78a60f8e42ebc8a7c47c149f3a9cc (patch)
treee5b79ad04cdec310dd53a2c2de5827366d79aa0b
parent7ace40ec22f23a9df78fdbee54fc44e6e30fb1dc (diff)
downloadgo-779b2c6eaca78a60f8e42ebc8a7c47c149f3a9cc.tar.xz
encoding/json: realign struct encodeState, structFields, and field
This reduce the struct encodeState size from 56 to 16 bytes (-42), struct structFields size from 40 to 24 bytes (-16), and struct field size from 136 to 128 bytes (-8). Benchmark memory profiling before and after, File: json.test Type: alloc_space Time: Jan 25, 2024 at 4:51am (WIB) Showing nodes accounting for -4.01GB, 4.66% of 85.95GB total Dropped 64 nodes (cum <= 0.43GB) flat flat% sum% cum cum% -4.25GB 4.94% 4.94% -4.01GB 4.67% encoding/json.Marshal 0.19GB 0.22% 4.73% 0.24GB 0.28% encoding/json.mapEncoder.encode 0.05GB 0.057% 4.67% 0.05GB 0.057% reflect.copyVal 0.04GB 0.049% 4.62% 0.04GB 0.049% bytes.growSlice -0.04GB 0.045% 4.66% -0.04GB 0.045% encoding/json.RawMessage.MarshalJSON 0 0% 4.66% 0.04GB 0.046% bytes.(*Buffer).WriteString 0 0% 4.66% 0.04GB 0.049% bytes.(*Buffer).grow 0 0% 4.66% -0.04GB 0.045% encoding/json.(*Encoder).Encode 0 0% 4.66% 0.20GB 0.23% encoding/json.(*encodeState).marshal 0 0% 4.66% 0.20GB 0.23% encoding/json.(*encodeState).reflectValue
-rw-r--r--src/encoding/json/encode.go20
1 files changed, 11 insertions, 9 deletions
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index 5e47413f23..0cca15b6e0 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -296,6 +296,8 @@ const hex = "0123456789abcdef"
// An encodeState encodes JSON into a bytes.Buffer.
type encodeState struct {
+ ptrSeen map[any]struct{}
+
bytes.Buffer // accumulated output
// Keep track of what pointers we've seen in the current recursive call
@@ -304,7 +306,6 @@ type encodeState struct {
// startDetectingCyclesAfter, so that we skip the work if we're within a
// reasonable amount of nested pointers deep.
ptrLevel uint
- ptrSeen map[any]struct{}
}
const startDetectingCyclesAfter = 1000
@@ -710,9 +711,9 @@ type structEncoder struct {
}
type structFields struct {
- list []field
byExactName map[string]*field
byFoldedName map[string]*field
+ list []field
}
func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
@@ -1068,21 +1069,22 @@ func appendString[Bytes []byte | string](dst []byte, src Bytes, escapeHTML bool)
// A field represents a single field found in a struct.
type field struct {
- name string
- nameBytes []byte // []byte(name)
+ encoder encoderFunc
+
+ typ reflect.Type
+ name string
nameNonEsc string // `"` + name + `":`
nameEscHTML string // `"` + HTMLEscape(name) + `":`
- tag bool
index []int
- typ reflect.Type
+ nameBytes []byte // []byte(name)
+
+ tag bool
omitEmpty bool
omitZero bool
isZero func(reflect.Value) bool
quoted bool
-
- encoder encoderFunc
}
type isZeroer interface {
@@ -1308,7 +1310,7 @@ func typeFields(t reflect.Type) structFields {
foldedNameIndex[string(foldName(field.nameBytes))] = &fields[i]
}
}
- return structFields{fields, exactNameIndex, foldedNameIndex}
+ return structFields{exactNameIndex, foldedNameIndex, fields}
}
// dominantField looks through the fields, all of which are known to