allocator.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. Copyright 2020 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package value
  14. // Allocator provides a value object allocation strategy.
  15. // Value objects can be allocated by passing an allocator to the "Using"
  16. // receiver functions on the value interfaces, e.g. Map.ZipUsing(allocator, ...).
  17. // Value objects returned from "Using" functions should be given back to the allocator
  18. // once longer needed by calling Allocator.Free(Value).
  19. type Allocator interface {
  20. // Free gives the allocator back any value objects returned by the "Using"
  21. // receiver functions on the value interfaces.
  22. // interface{} may be any of: Value, Map, List or Range.
  23. Free(interface{})
  24. // The unexported functions are for "Using" receiver functions of the value types
  25. // to request what they need from the allocator.
  26. allocValueUnstructured() *valueUnstructured
  27. allocListUnstructuredRange() *listUnstructuredRange
  28. allocValueReflect() *valueReflect
  29. allocMapReflect() *mapReflect
  30. allocStructReflect() *structReflect
  31. allocListReflect() *listReflect
  32. allocListReflectRange() *listReflectRange
  33. }
  34. // HeapAllocator simply allocates objects to the heap. It is the default
  35. // allocator used receiver functions on the value interfaces that do not accept
  36. // an allocator and should be used whenever allocating objects that will not
  37. // be given back to an allocator by calling Allocator.Free(Value).
  38. var HeapAllocator = &heapAllocator{}
  39. type heapAllocator struct{}
  40. func (p *heapAllocator) allocValueUnstructured() *valueUnstructured {
  41. return &valueUnstructured{}
  42. }
  43. func (p *heapAllocator) allocListUnstructuredRange() *listUnstructuredRange {
  44. return &listUnstructuredRange{vv: &valueUnstructured{}}
  45. }
  46. func (p *heapAllocator) allocValueReflect() *valueReflect {
  47. return &valueReflect{}
  48. }
  49. func (p *heapAllocator) allocStructReflect() *structReflect {
  50. return &structReflect{}
  51. }
  52. func (p *heapAllocator) allocMapReflect() *mapReflect {
  53. return &mapReflect{}
  54. }
  55. func (p *heapAllocator) allocListReflect() *listReflect {
  56. return &listReflect{}
  57. }
  58. func (p *heapAllocator) allocListReflectRange() *listReflectRange {
  59. return &listReflectRange{vr: &valueReflect{}}
  60. }
  61. func (p *heapAllocator) Free(_ interface{}) {}
  62. // NewFreelistAllocator creates freelist based allocator.
  63. // This allocator provides fast allocation and freeing of short lived value objects.
  64. //
  65. // The freelists are bounded in size by freelistMaxSize. If more than this amount of value objects is
  66. // allocated at once, the excess will be returned to the heap for garbage collection when freed.
  67. //
  68. // This allocator is unsafe and must not be accessed concurrently by goroutines.
  69. //
  70. // This allocator works well for traversal of value data trees. Typical usage is to acquire
  71. // a freelist at the beginning of the traversal and use it through out
  72. // for all temporary value access.
  73. func NewFreelistAllocator() Allocator {
  74. return &freelistAllocator{
  75. valueUnstructured: &freelist{new: func() interface{} {
  76. return &valueUnstructured{}
  77. }},
  78. listUnstructuredRange: &freelist{new: func() interface{} {
  79. return &listUnstructuredRange{vv: &valueUnstructured{}}
  80. }},
  81. valueReflect: &freelist{new: func() interface{} {
  82. return &valueReflect{}
  83. }},
  84. mapReflect: &freelist{new: func() interface{} {
  85. return &mapReflect{}
  86. }},
  87. structReflect: &freelist{new: func() interface{} {
  88. return &structReflect{}
  89. }},
  90. listReflect: &freelist{new: func() interface{} {
  91. return &listReflect{}
  92. }},
  93. listReflectRange: &freelist{new: func() interface{} {
  94. return &listReflectRange{vr: &valueReflect{}}
  95. }},
  96. }
  97. }
  98. // Bound memory usage of freelists. This prevents the processing of very large lists from leaking memory.
  99. // This limit is large enough for endpoints objects containing 1000 IP address entries. Freed objects
  100. // that don't fit into the freelist are orphaned on the heap to be garbage collected.
  101. const freelistMaxSize = 1000
  102. type freelistAllocator struct {
  103. valueUnstructured *freelist
  104. listUnstructuredRange *freelist
  105. valueReflect *freelist
  106. mapReflect *freelist
  107. structReflect *freelist
  108. listReflect *freelist
  109. listReflectRange *freelist
  110. }
  111. type freelist struct {
  112. list []interface{}
  113. new func() interface{}
  114. }
  115. func (f *freelist) allocate() interface{} {
  116. var w2 interface{}
  117. if n := len(f.list); n > 0 {
  118. w2, f.list = f.list[n-1], f.list[:n-1]
  119. } else {
  120. w2 = f.new()
  121. }
  122. return w2
  123. }
  124. func (f *freelist) free(v interface{}) {
  125. if len(f.list) < freelistMaxSize {
  126. f.list = append(f.list, v)
  127. }
  128. }
  129. func (w *freelistAllocator) Free(value interface{}) {
  130. switch v := value.(type) {
  131. case *valueUnstructured:
  132. v.Value = nil // don't hold references to unstructured objects
  133. w.valueUnstructured.free(v)
  134. case *listUnstructuredRange:
  135. v.vv.Value = nil // don't hold references to unstructured objects
  136. w.listUnstructuredRange.free(v)
  137. case *valueReflect:
  138. v.ParentMapKey = nil
  139. v.ParentMap = nil
  140. w.valueReflect.free(v)
  141. case *mapReflect:
  142. w.mapReflect.free(v)
  143. case *structReflect:
  144. w.structReflect.free(v)
  145. case *listReflect:
  146. w.listReflect.free(v)
  147. case *listReflectRange:
  148. v.vr.ParentMapKey = nil
  149. v.vr.ParentMap = nil
  150. w.listReflectRange.free(v)
  151. }
  152. }
  153. func (w *freelistAllocator) allocValueUnstructured() *valueUnstructured {
  154. return w.valueUnstructured.allocate().(*valueUnstructured)
  155. }
  156. func (w *freelistAllocator) allocListUnstructuredRange() *listUnstructuredRange {
  157. return w.listUnstructuredRange.allocate().(*listUnstructuredRange)
  158. }
  159. func (w *freelistAllocator) allocValueReflect() *valueReflect {
  160. return w.valueReflect.allocate().(*valueReflect)
  161. }
  162. func (w *freelistAllocator) allocStructReflect() *structReflect {
  163. return w.structReflect.allocate().(*structReflect)
  164. }
  165. func (w *freelistAllocator) allocMapReflect() *mapReflect {
  166. return w.mapReflect.allocate().(*mapReflect)
  167. }
  168. func (w *freelistAllocator) allocListReflect() *listReflect {
  169. return w.listReflect.allocate().(*listReflect)
  170. }
  171. func (w *freelistAllocator) allocListReflectRange() *listReflectRange {
  172. return w.listReflectRange.allocate().(*listReflectRange)
  173. }