mirror of https://github.com/goccy/go-json.git
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
This commit is contained in:
parent
3e9769d637
commit
279389a781
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -17,22 +18,27 @@ var (
|
||||||
typeAddr *runtime.TypeAddr
|
typeAddr *runtime.TypeAddr
|
||||||
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
||||||
cachedDecoder []Decoder
|
cachedDecoder []Decoder
|
||||||
|
initOnce sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func initDecoder() {
|
||||||
|
initOnce.Do(func() {
|
||||||
typeAddr = runtime.AnalyzeTypeAddr()
|
typeAddr = runtime.AnalyzeTypeAddr()
|
||||||
if typeAddr == nil {
|
if typeAddr == nil {
|
||||||
typeAddr = &runtime.TypeAddr{}
|
typeAddr = &runtime.TypeAddr{}
|
||||||
}
|
}
|
||||||
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
|
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadDecoderMap() map[uintptr]Decoder {
|
func loadDecoderMap() map[uintptr]Decoder {
|
||||||
|
initDecoder()
|
||||||
p := atomic.LoadPointer(&cachedDecoderMap)
|
p := atomic.LoadPointer(&cachedDecoderMap)
|
||||||
return *(*map[uintptr]Decoder)(unsafe.Pointer(&p))
|
return *(*map[uintptr]Decoder)(unsafe.Pointer(&p))
|
||||||
}
|
}
|
||||||
|
|
||||||
func storeDecoder(typ uintptr, dec Decoder, m map[uintptr]Decoder) {
|
func storeDecoder(typ uintptr, dec Decoder, m map[uintptr]Decoder) {
|
||||||
|
initDecoder()
|
||||||
newDecoderMap := make(map[uintptr]Decoder, len(m)+1)
|
newDecoderMap := make(map[uintptr]Decoder, len(m)+1)
|
||||||
newDecoderMap[typ] = dec
|
newDecoderMap[typ] = dec
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
|
func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
|
||||||
|
initDecoder()
|
||||||
typeptr := uintptr(unsafe.Pointer(typ))
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
if typeptr > typeAddr.MaxTypeAddr {
|
if typeptr > typeAddr.MaxTypeAddr {
|
||||||
return compileToGetDecoderSlowPath(typeptr, typ)
|
return compileToGetDecoderSlowPath(typeptr, typ)
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
var decMu sync.RWMutex
|
var decMu sync.RWMutex
|
||||||
|
|
||||||
func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
|
func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
|
||||||
|
initDecoder()
|
||||||
typeptr := uintptr(unsafe.Pointer(typ))
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
if typeptr > typeAddr.MaxTypeAddr {
|
if typeptr > typeAddr.MaxTypeAddr {
|
||||||
return compileToGetDecoderSlowPath(typeptr, typ)
|
return compileToGetDecoderSlowPath(typeptr, typ)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding"
|
"encoding"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
@ -24,14 +25,17 @@ var (
|
||||||
cachedOpcodeSets []*OpcodeSet
|
cachedOpcodeSets []*OpcodeSet
|
||||||
cachedOpcodeMap unsafe.Pointer // map[uintptr]*OpcodeSet
|
cachedOpcodeMap unsafe.Pointer // map[uintptr]*OpcodeSet
|
||||||
typeAddr *runtime.TypeAddr
|
typeAddr *runtime.TypeAddr
|
||||||
|
initEncoderOnce sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func initEncoder() {
|
||||||
|
initEncoderOnce.Do(func() {
|
||||||
typeAddr = runtime.AnalyzeTypeAddr()
|
typeAddr = runtime.AnalyzeTypeAddr()
|
||||||
if typeAddr == nil {
|
if typeAddr == nil {
|
||||||
typeAddr = &runtime.TypeAddr{}
|
typeAddr = &runtime.TypeAddr{}
|
||||||
}
|
}
|
||||||
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
|
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadOpcodeMap() map[uintptr]*OpcodeSet {
|
func loadOpcodeMap() map[uintptr]*OpcodeSet {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package encoder
|
package encoder
|
||||||
|
|
||||||
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
|
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
|
||||||
|
initEncoder()
|
||||||
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
|
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
|
||||||
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
|
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
var setsMu sync.RWMutex
|
var setsMu sync.RWMutex
|
||||||
|
|
||||||
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
|
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
|
||||||
|
initEncoder()
|
||||||
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
|
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
|
||||||
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
|
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue