diff --git a/decoder/decoder.go b/decoder/decoder.go index 8544327..9dc430f 100644 --- a/decoder/decoder.go +++ b/decoder/decoder.go @@ -19,6 +19,7 @@ package decoder import ( `encoding/json` `reflect` + `runtime` `github.com/bytedance/sonic/internal/rt` ) @@ -70,6 +71,9 @@ func (self *Decoder) Decode(val interface{}) error { /* return the stack back */ self.i = nb freeStack(sb) + + /* avoid GC ahead */ + runtime.KeepAlive(vv) return err } @@ -105,4 +109,4 @@ func (self *Decoder) DisallowUnknownFields() { func Pretouch(vt reflect.Type) (err error) { _, err = findOrCompile(rt.UnpackType(vt)) return -} +} \ No newline at end of file diff --git a/encoder/encoder.go b/encoder/encoder.go index 3a58838..61d4c87 100644 --- a/encoder/encoder.go +++ b/encoder/encoder.go @@ -20,6 +20,7 @@ import ( `bytes` `encoding/json` `reflect` + `runtime` `github.com/bytedance/sonic/internal/rt` ) @@ -102,6 +103,9 @@ func EncodeInto(buf *[]byte, val interface{}, opts Options) error { /* return the stack into pool */ freeStack(stk) + + /* avoid GC ahead */ + runtime.KeepAlive(efv) return err } diff --git a/issue_test/issue123_test.go b/issue_test/issue123_test.go new file mode 100644 index 0000000..7b66ad1 --- /dev/null +++ b/issue_test/issue123_test.go @@ -0,0 +1,63 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package issue_test + +import ( + `encoding/json` + `fmt` + `sync` + `testing` + + `github.com/bytedance/sonic` +) + +func TestGcWriteBarrier(t *testing.T) { + // debug.SetGCPercent(-1) + size := 10_0000 + data := make([]int, size) + date, _ := json.Marshal(data) + + // debug.SetGCPercent(-1) + wg := sync.WaitGroup{} + + for i := 0; i < 1000; i++ { + wg.Add(1) + cd := make([]byte, len(date)) + copy(cd, date) + go func() { + var w []int + defer wg.Done() + // Decode + if err := sonic.Unmarshal(cd, &w); err != nil { + fmt.Println(err) + } + }() + } + wg.Wait() +} + +func BenchmarkGcGuard(b *testing.B) { + size := 10_0000 + data := make([]int, size) + date, _ := json.Marshal(data) + b.RunParallel(func(p *testing.PB) { + for p.Next() { + var w []int + _ = sonic.Unmarshal(date, &w) + } + }) +} \ No newline at end of file