-
Notifications
You must be signed in to change notification settings - Fork 53
/
alloc.go
89 lines (71 loc) · 1.54 KB
/
alloc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package goparquet
import (
"fmt"
"reflect"
"runtime"
"sync"
)
type allocTracker struct {
mtx sync.RWMutex
allocs map[uintptr]uint64
totalSize uint64
maxSize uint64
}
func newAllocTracker(maxSize uint64) *allocTracker {
return &allocTracker{
allocs: make(map[uintptr]uint64),
maxSize: maxSize,
}
}
func (t *allocTracker) register(obj interface{}, size uint64) {
if t == nil {
return
}
t.mtx.Lock()
defer t.mtx.Unlock()
if _, ok := obj.([]byte); ok {
obj = &obj
}
key := reflect.ValueOf(obj).Pointer()
if _, ok := t.allocs[key]; ok { // object has already been tracked, no need to add it.
t.mtx.Unlock()
return
}
t.allocs[key] = size
t.totalSize += size
runtime.SetFinalizer(obj, t.finalize)
if t.maxSize > 0 && t.totalSize > t.maxSize {
t.doPanic(t.totalSize)
}
}
func (t *allocTracker) test(size uint64) {
if t == nil {
return
}
t.mtx.RLock()
defer t.mtx.RUnlock()
if t.maxSize > 0 && t.totalSize+size > t.maxSize {
t.doPanic(t.totalSize + size)
}
}
func (t *allocTracker) doPanic(totalSize uint64) {
if t == nil {
return
}
panic(fmt.Errorf("memory usage of %d bytes is greater than configured maximum of %d bytes", totalSize, t.maxSize))
}
func (t *allocTracker) finalize(obj interface{}) {
if t == nil {
return
}
t.mtx.Lock()
defer t.mtx.Unlock()
key := reflect.ValueOf(obj).Pointer()
size, ok := t.allocs[key]
if !ok { // if object hasn't been tracked, do nothing.
return
}
// remove size from total size, and unregister from tracker.
t.totalSize -= size
delete(t.allocs, key)
}