Skip to content

Commit 279389a

Browse files
authored
Fix: Switch to lazy init() in decoder and encoder (#490)
* Switch to lazy init() in decoder and encoder This will prevent go-json from consuming heap unless it is used. * limit changes to initEncoder and initDecoder
1 parent 3e9769d commit 279389a

File tree

6 files changed

+26
-12
lines changed

6 files changed

+26
-12
lines changed

internal/decoder/compile.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"reflect"
77
"strings"
8+
"sync"
89
"sync/atomic"
910
"unicode"
1011
"unsafe"
@@ -17,22 +18,27 @@ var (
1718
typeAddr *runtime.TypeAddr
1819
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
1920
cachedDecoder []Decoder
21+
initOnce sync.Once
2022
)
2123

22-
func init() {
23-
typeAddr = runtime.AnalyzeTypeAddr()
24-
if typeAddr == nil {
25-
typeAddr = &runtime.TypeAddr{}
26-
}
27-
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
24+
func initDecoder() {
25+
initOnce.Do(func() {
26+
typeAddr = runtime.AnalyzeTypeAddr()
27+
if typeAddr == nil {
28+
typeAddr = &runtime.TypeAddr{}
29+
}
30+
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
31+
})
2832
}
2933

3034
func loadDecoderMap() map[uintptr]Decoder {
35+
initDecoder()
3136
p := atomic.LoadPointer(&cachedDecoderMap)
3237
return *(*map[uintptr]Decoder)(unsafe.Pointer(&p))
3338
}
3439

3540
func storeDecoder(typ uintptr, dec Decoder, m map[uintptr]Decoder) {
41+
initDecoder()
3642
newDecoderMap := make(map[uintptr]Decoder, len(m)+1)
3743
newDecoderMap[typ] = dec
3844

internal/decoder/compile_norace.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
)
1111

1212
func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
13+
initDecoder()
1314
typeptr := uintptr(unsafe.Pointer(typ))
1415
if typeptr > typeAddr.MaxTypeAddr {
1516
return compileToGetDecoderSlowPath(typeptr, typ)

internal/decoder/compile_race.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
var decMu sync.RWMutex
1414

1515
func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
16+
initDecoder()
1617
typeptr := uintptr(unsafe.Pointer(typ))
1718
if typeptr > typeAddr.MaxTypeAddr {
1819
return compileToGetDecoderSlowPath(typeptr, typ)

internal/encoder/compiler.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding"
66
"encoding/json"
77
"reflect"
8+
"sync"
89
"sync/atomic"
910
"unsafe"
1011

@@ -24,14 +25,17 @@ var (
2425
cachedOpcodeSets []*OpcodeSet
2526
cachedOpcodeMap unsafe.Pointer // map[uintptr]*OpcodeSet
2627
typeAddr *runtime.TypeAddr
28+
initEncoderOnce sync.Once
2729
)
2830

29-
func init() {
30-
typeAddr = runtime.AnalyzeTypeAddr()
31-
if typeAddr == nil {
32-
typeAddr = &runtime.TypeAddr{}
33-
}
34-
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
31+
func initEncoder() {
32+
initEncoderOnce.Do(func() {
33+
typeAddr = runtime.AnalyzeTypeAddr()
34+
if typeAddr == nil {
35+
typeAddr = &runtime.TypeAddr{}
36+
}
37+
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
38+
})
3539
}
3640

3741
func loadOpcodeMap() map[uintptr]*OpcodeSet {

internal/encoder/compiler_norace.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package encoder
55

66
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
7+
initEncoder()
78
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
89
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
910
if err != nil {

internal/encoder/compiler_race.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
var setsMu sync.RWMutex
1111

1212
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
13+
initEncoder()
1314
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
1415
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
1516
if err != nil {

0 commit comments

Comments
 (0)