Documentation ¶
Overview ¶
Usage ¶
The offheap package allows us to allocate, free and retrieve Go objects manually. The objects allocated in this way are not visible to the garbage collector, allowing us to build very large datastructures like trees and hashmaps without impacting garbage collection efficiency.
Each Store instance can allocate/free a wide variety of object types. Broadly we can allocate _any_ Go type so long as no part of the type contains pointers. We can allocate slices of pointerless types with a dedicated slice type. And finally we can allocate strings through a dedicated string type.
Each allocation has a corresponding Reference, named RefObject, RefSlice and RefString respectively, which acts like a conventional pointer to retrieve the allocated object via Reference.Value() e.g.
var store *offheap.Store = offheap.New() var ref offheap.RefObject[int] = offheap.AllocObject[int](store) var i1 *int = ref.Value()
When you know that an allocation will never be used again it's memory can be released back to the Store using one of the Free*() functions e.g.
var store *offheap.Store = offheap.New() var ref offheap.RefObject[int] = offheap.AllocObject[int](store) offheap.FreeObject(store, ref) // You must never use ref again
A best effort has been made to panic if an object is freed twice or if a freed object is accessed using Reference.Value(). However, it isn't guaranteed that these calls will panic.
References can be kept and stored in arbitrary datastructures, which can themselves be managed by a Store e.g.
type Node struct { left offheap.RefObject[Node] right offheap.RefObject[Node] } var store *offheap.Store = offheap.New() var refParent offheap.RefObject[Node] = offheap.AllocObject[Node]((store))
The Reference types contain no conventional Go pointers which are recognised by the garbage collector.
It is important to note that the objects managed by a Store do not exist on the managed Go heap. They live in a series of manually mapped memory regions which are managed separately by the Store. This means that the amount of memory used by the Store has no impact on the frequency of garbage collection runs.
Not all pointers in Go types are obvious. Here are a few examples of types which can't be managed in a Store.
type BadStruct1 struct { stringsHavePointers string } type BadStruct2 struct { mapsHavePointers map[int]int } type BadStruct3 struct { slicesHavePointers []int } type BadStruct4 struct { pointersHavePointers *int } type BadStruct5 struct { storesHavePointers *Store }
Trying to allocate an object or slice with a generic type which contains pointers will panic.
Memory Model Constraints:
A Store has a moderate degree of concurrency safety, but users must still be careful how they access and modify data allocated by a Store instance. A shorter version of the guarantees described below would be to say that allocating and retrieving objects managed by a Store has the same guarantees and limitations that conventionally allocated Go objects have.
Concurrency Guarantees ¶
1: Independent Alloc/Free Safety
It is safe for multiple goroutines using a shared Store instance to call Alloc() and Free() generating independent sets of objects/References. They can safely read the objects they have allocated without any additional concurrency protection.
2: Safe Data Publication
It is safe to create objects using Alloc() and then share those objects with other goroutines. We must establish the usual happens-before relationships when sharing objects/References with other goroutines.
For example it is safe to Alloc() new objects and publish References to those objects on a channel and have other goroutines read from that channel and call Reference.Value() on those References.
3: Independent Read Safety
For a given set of live objects, previously allocated with a happens-before barrier between the allocator and readers, all objects can be read freely. Calling Reference.Value() and performing arbitrary reads of the retrieved objects from multiple goroutines with no other concurrency control code will work without data races.
4: Safe Object Reads And Writes
It is not safe for multiple goroutines to freely write to the object, nor to have multiple goroutines freely perform a mixture of read/write operations on the object. You can however perform concurrent reads and writes to a shared object if you use appropriate concurrency controls such as sync.Mutex.
5: Free Safety
If we call Free() on the same Reference (a Reference pointing to the same allocation) concurrently from two or more goroutines this will be a data race. The behaviour is unpredictable in this case. This is also a bug, but potentially one with stranger behaviour than just calling Free() twice from a single goroutine.
If we call Free() on a Reference while another goroutine is calling Reference.Value() this is a data race. This will have unpredictable behaviour, and is never safe.
Index ¶
- func ConfForSlice[T any](s *Store, capacity int) pointerstore.AllocConfig
- func ConfForString(s *Store, length int) pointerstore.AllocConfig
- func ConfForType[T any](s *Store) pointerstore.AllocConfig
- func FreeObject[T any](s *Store, r RefObject[T])
- func FreeSlice[T any](s *Store, r RefSlice[T])
- func FreeString(s *Store, r RefString)
- func StatsForSlice[T any](s *Store, capacity int) pointerstore.Stats
- func StatsForString(s *Store, length int) pointerstore.Stats
- func StatsForType[T any](s *Store) pointerstore.Stats
- type RefObject
- type RefSlice
- type RefString
- type Reference
- type Store
Examples ¶
- AllocObject
- AllocObject (BadTypeMap)
- AllocObject (BadTypePointer)
- AllocObject (BadTypeSlice)
- AllocObject (BadTypeString)
- AllocObject (ComplexType)
- AllocSlice
- AllocStringFromBytes
- AllocStringFromString
- Append
- Append (OldRef)
- AppendSlice
- AppendSlice (OldRef)
- AppendString
- AppendString (OldRef)
- ConcatSlices
- ConcatStrings
- FreeObject
- FreeObject (UseAfterFreePanics)
- Reference (RefObject)
- Reference (RefSlice)
- Reference (RefString)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ConfForSlice ¶
func ConfForSlice[T any](s *Store, capacity int) pointerstore.AllocConfig
Returns the allocation config for the allocation size of a []T with capacity.
It is important to note that this config apply to the size class indicated here. The config apply to all allocations for this _size_ including allocations for non-slice types.
func ConfForString ¶
func ConfForString(s *Store, length int) pointerstore.AllocConfig
Returns the allocation config for the allocations size of a string of length.
It is important to note that this config apply to the size class indicated here. The config apply to all allocations for this _size_ including allocations for non-string types.
func ConfForType ¶
func ConfForType[T any](s *Store) pointerstore.AllocConfig
Returns the allocation config for the allocation size of type T
It is important to note that this config apply to the size class indicated by T. The config apply to all allocations for this _size_ including allocations for types other than T.
func FreeObject ¶
Frees the allocation referenced by r. After this call returns r must never be used again. Any use of the object referenced by r will have unpredicatable behaviour.
Example ¶
You can free memory used by an an allocated object by calling FreeObject(...). The RefObject can no longer be used, and the use of the actual object pointed to will have unpredicatable results.
package main import ( "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref offheap.RefObject[int] = offheap.AllocObject[int](store) offheap.FreeObject(store, ref) // You must never use ref again }
Output:
Example (UseAfterFreePanics) ¶
You can free memory used by an an allocated object by calling FreeObject(...). The RefObject can no longer be used, and the use of the actual object pointed to will have unpredicatable results.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref offheap.RefObject[int] = offheap.AllocObject[int](store) offheap.FreeObject(store, ref) // You must never use ref again defer func() { if err := recover(); err != nil { fmt.Println("Use after free panics") } }() ref.Value() }
Output: Use after free panics
func FreeSlice ¶
Frees the allocation referenced by r. After this call returns r must never be used again. Any use of the slice referenced by r will have unpredicatable behaviour.
func FreeString ¶
Frees the allocation referenced by r. After this call returns r must never be used again. Any use of the string referenced by r will have unpredicatable behaviour.
func StatsForSlice ¶
func StatsForSlice[T any](s *Store, capacity int) pointerstore.Stats
Returns the stats for the allocation size of a []T with capacity.
It is important to note that these statistics apply to the size class indicated here. The statistics allocations will capture all allocations for this _size_ including allocations for non-slice types.
func StatsForString ¶
func StatsForString(s *Store, length int) pointerstore.Stats
Returns the stats for the allocations size of a string of length.
It is important to note that these statistics apply to the size class indicated here. The statistics allocations will capture all allocations for this _size_ including allocations for non-slice types.
func StatsForType ¶
func StatsForType[T any](s *Store) pointerstore.Stats
Returns the stats for the allocation size of type T.
It is important to note that these statistics apply to the size class indicated by T. The statistics allocations will capture all allocations for this _size_ including allocations for types other than T.
Types ¶
type RefObject ¶
type RefObject[T any] struct { // contains filtered or unexported fields }
A reference to a typed object. This reference allows us to gain access to an allocated object directly.
It is acceptable, and enouraged, to use RefObject in fields of types which will be managed by a Store. This is acceptable because RefObject does not contain any conventional Go pointers.
func AllocObject ¶
Allocates an object of type T. The type T must not contain any pointers in any part of its type. If the type T is found to contain pointers this function will panic.
The values of fields in the newly allocated object will be arbitrary. Unlike Go allocations objects acquired via AllocObject do _not_ have their contents zeroed out.
Example ¶
Calling AllocObject allocates an object and returns a RefObject which acts like a conventional pointer through which you can retrieve the allocated object via RefObject.Value()
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref offheap.RefObject[int] = offheap.AllocObject[int](store) var i1 *int = ref.Value() var i2 *int = ref.Value() if i1 == i2 { fmt.Println("This is correct, i1 and i2 are pointers to the same int location") } }
Output: This is correct, i1 and i2 are pointers to the same int location
Example (BadTypeMap) ¶
You cannot allocate a map type. Maps contain pointers interally and are not allowed.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { type BadStruct struct { //lint:ignore U1000 this field looks unused but is observed by reflection mapsHavePointers map[int]int } defer func() { if err := recover(); err != nil { fmt.Println("Can't allocate maps") } }() var store *offheap.Store = offheap.New() offheap.AllocObject[BadStruct](store) }
Output: Can't allocate maps
Example (BadTypePointer) ¶
You cannot allocate a pointer type (obviously).
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { type BadStruct struct { //lint:ignore U1000 this field looks unused but is observed by reflection pointersHavePointers *int } defer func() { if err := recover(); err != nil { fmt.Println("Can't allocate pointers") } }() var store *offheap.Store = offheap.New() offheap.AllocObject[BadStruct](store) }
Output: Can't allocate pointers
Example (BadTypeSlice) ¶
You cannot allocate a slice type. Slices contain pointers interally and are not allowed.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { type BadStruct struct { //lint:ignore U1000 this field looks unused but is observed by reflection slicesHavePointers []int } defer func() { if err := recover(); err != nil { fmt.Println("Can't allocate slices (as an object)") } }() var store *offheap.Store = offheap.New() offheap.AllocObject[BadStruct](store) }
Output: Can't allocate slices (as an object)
Example (BadTypeString) ¶
You cannot allocate a string type. Strings contain pointers interally and are not allowed.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { type BadStruct struct { //lint:ignore U1000 this field looks unused but is observed by reflection stringsHavePointers string } defer func() { if err := recover(); err != nil { fmt.Println("Can't allocate strings") } }() var store *offheap.Store = offheap.New() offheap.AllocObject[BadStruct](store) }
Output: Can't allocate strings
Example (ComplexType) ¶
You can allocate objects of complex types, including types with fields which are also of type RefObject. This allows us to build large datastructures, like trees in this example.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { type Node struct { left offheap.RefObject[Node] right offheap.RefObject[Node] } var store *offheap.Store = offheap.New() var refParent offheap.RefObject[Node] = offheap.AllocObject[Node]((store)) var parent *Node = refParent.Value() var refLeft offheap.RefObject[Node] = offheap.AllocObject[Node]((store)) parent.left = refLeft var refRight offheap.RefObject[Node] = offheap.AllocObject[Node]((store)) parent.right = refRight // Re-get the parent pointer var reGetParent *Node = refParent.Value() if reGetParent.left == refLeft && reGetParent.right == refRight { fmt.Println("The mutations of the parent Node are visible via the reference") } }
Output: The mutations of the parent Node are visible via the reference
type RefSlice ¶
type RefSlice[T any] struct { // contains filtered or unexported fields }
A reference to a slice. This reference allows us to gain access to an allocated slice directly.
It is acceptable, and enouraged, to use RefSlice in fields of types which will be managed by a Store. This is acceptable because RefSlice does not contain any conventional Go pointers, unlike native slices.
func AllocSlice ¶
Allocates a new slice with the desired length and capacity. The capacity of the actual slice may not be the same as requestedCapacity, but it will never be smaller than requestedCapacity.
The contents of the slice will be arbitrary. Unlike Go slices acquired via AllocSlice do _not_ have their contents zeroed out.
Example ¶
Calling AllocSlice allocates a slice and returns a RefSlice which acts like a conventional pointer through which you can retrieve the allocated slice via RefSlice.Value()
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref offheap.RefSlice[int] = offheap.AllocSlice[int](store, 1, 2) // Set the first element in the allocated slice var s1 []int = ref.Value() s1[0] = 1 // Show that the first element write is visible to other reads var s2 []int = ref.Value() fmt.Printf("Slice of %v with length %d and capacity %d", s2, len(s2), cap(s1)) }
Output: Slice of [1] with length 1 and capacity 2
func Append ¶
Returns a new RefSlice pointing to a slice whose size and contents is the same as append(into.Value(), value).
After this function returns into is no longer a valid RefSlice, and will behave as if Free(...) was called on it. Internally there is an optimisation which _may_ reuse the existing allocation slot if possible. But externally this function behaves as if a new allocation is made and the old one freed.
Example ¶
You can append an element to an allocated RefSlice
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref1 offheap.RefSlice[int] = offheap.AllocSlice[int](store, 1, 2) // Set the first element in the allocated slice var s1 []int = ref1.Value() s1[0] = 1 // Append a second element to the slice var ref2 offheap.RefSlice[int] = offheap.Append(store, ref1, 2) var s2 []int = ref2.Value() fmt.Printf("Slice of %v with length %d and capacity %d", s2, len(s2), cap(s1)) }
Output: Slice of [1 2] with length 2 and capacity 2
Example (OldRef) ¶
After call to append the old RefSlice is no longer valid for use
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref1 offheap.RefSlice[int] = offheap.AllocSlice[int](store, 1, 2) // Set the first element in the allocated slice var s1 []int = ref1.Value() s1[0] = 1 // Append a second element to the slice offheap.Append(store, ref1, 2) defer func() { if err := recover(); err != nil { fmt.Printf("The RefSlice passed into Append cannot be used after") } }() ref1.Value() }
Output: The RefSlice passed into Append cannot be used after
func AppendSlice ¶
Returns a new RefSlice pointing to a slice whose size and contents is the same as append(into.Value(), fromSlice...).
After this function returns into is no longer a valid RefSlice, and will behave as if Free(...) was called on it. Internally there is an optimisation which _may_ reuse the existing allocation slot if possible. But externally this function behaves as if a new allocation is made and the old one freed.
Example ¶
You can append a slice to a RefSlice. This will create a new RefSlice with the original slice and the slice passed in appended together.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref1 offheap.RefSlice[int] = offheap.AllocSlice[int](store, 1, 2) // Set the first element in the allocated slice var s1 []int = ref1.Value() s1[0] = 1 // Append a second element to the slice var ref2 offheap.RefSlice[int] = offheap.AppendSlice(store, ref1, []int{2, 3}) var s2 []int = ref2.Value() fmt.Printf("Slice of %v with length %d and capacity %d", s2, len(s2), cap(s2)) }
Output: Slice of [1 2 3] with length 3 and capacity 4
Example (OldRef) ¶
After call to AppendSlice the old RefSlice is no longer valid for use.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref1 offheap.RefSlice[int] = offheap.AllocSlice[int](store, 1, 2) // Set the first element in the allocated slice var s1 []int = ref1.Value() s1[0] = 1 // Append a second element to the slice offheap.AppendSlice(store, ref1, []int{2, 3}) defer func() { if err := recover(); err != nil { fmt.Printf("The RefSlice passed into AppendSlice cannot be used after") } }() ref1.Value() }
Output: The RefSlice passed into AppendSlice cannot be used after
func ConcatSlices ¶
Allocates a new slice which contains the elements of slices concatenated together
Example ¶
You can allocate a RefSlice by passing in a number of slices to be concatenated together
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() slice1 := []int{1, 2} slice2 := []int{3, 4} slice3 := []int{5, 6} var ref offheap.RefSlice[int] = offheap.ConcatSlices[int](store, slice1, slice2, slice3) var s1 []int = ref.Value() fmt.Printf("Slice of %v with length %d and capacity %d", s1, len(s1), cap(s1)) }
Output: Slice of [1 2 3 4 5 6] with length 6 and capacity 8
type RefString ¶
type RefString struct {
// contains filtered or unexported fields
}
A reference to a string. This reference allows us to gain access to an allocated string directly.
It is acceptable, and enouraged, to use RefString in fields of types which will be managed by a Store. This is acceptable because RefString does not contain any conventional Go pointers, unlike native strings.
func AllocStringFromBytes ¶
Allocates a new string whose size and contents will be the same as found in bytes.
Example ¶
Calling AllocStringFromBytes allocates a string and returns a RefString which acts like a conventional pointer through which you can retrieve the allocated string via RefString.Value()
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref offheap.RefString = offheap.AllocStringFromBytes(store, []byte("allocated")) // Set the first element in the allocated slice var s1 string = ref.Value() fmt.Printf("String of %q", s1) }
Output: String of "allocated"
func AllocStringFromString ¶
Allocates a new string whose size and contents will be the same as found in str.
Example ¶
Calling AllocStringFromString allocates a string and returns a RefString which acts like a conventional pointer through which you can retrieve the allocated string via RefString.Value()
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref offheap.RefString = offheap.AllocStringFromString(store, "allocated") // Set the first element in the allocated slice var s1 string = ref.Value() fmt.Printf("String of %q", s1) }
Output: String of "allocated"
func AppendString ¶
Returns a new RefString pointing to a string whose size and contents is the same as into.Value() + value.
After this function returns into is no longer a valid RefString, and will behave as if Free(...) was called on it. Internally there is an optimisation which _may_ reuse the existing allocation slot if possible. But externally this function behaves as if a new allocation is made and the old one freed.
Example ¶
You can append a string to an allocated RefString
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref1 offheap.RefString = offheap.AllocStringFromString(store, "allocated") // AppendString a second element to the string var ref2 offheap.RefString = offheap.AppendString(store, ref1, " and appended") var s2 string = ref2.Value() fmt.Printf("String of %q", s2) }
Output: String of "allocated and appended"
Example (OldRef) ¶
After call to append the old RefString is no longer valid for use
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref1 offheap.RefString = offheap.AllocStringFromString(store, "allocated") // AppendString a second element to the string offheap.AppendString(store, ref1, " and appended") defer func() { if err := recover(); err != nil { fmt.Printf("The RefString passed into AppendString cannot be used after") } }() ref1.Value() }
Output: The RefString passed into AppendString cannot be used after
func ConcatStrings ¶
Allocates a new string which contains the elements of strs concatenated together.
Example ¶
You can allocate a RefString by passing in a number of strings to be concatenated together
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { var store *offheap.Store = offheap.New() var ref offheap.RefString = offheap.ConcatStrings(store, "all", "oca", "ted") var s1 string = ref.Value() fmt.Printf("String of %q", s1) }
Output: String of "allocated"
type Reference ¶
This type constraint allows us to build generic types which accept any Reference type. There is an awkward problem if your type is RefString, because you are forced to include an _unused_ parameterised type. We may learn to live with this peacefully in time.
Example (RefObject) ¶
Here we store and retrieve a RefObject[int] using a Reference typed container.
This example exists simply to illustrate how the Reference type can be used. I don't think it's obvious without at least one example.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { // The ReferenceMap type is capable of storing either RefString, // RefSlice or RefObject types type ReferenceMap[T any, R offheap.Reference[T]] struct { rMap map[int]R } // Here we instantiate a ReferenceMap which can store RefObject references var refObjectMap ReferenceMap[int, offheap.RefObject[int]] = ReferenceMap[int, offheap.RefObject[int]]{ rMap: make(map[int]offheap.RefObject[int]), } // Create a RefObject var store *offheap.Store = offheap.New() var ref offheap.RefObject[int] = offheap.AllocObject[int](store) var intValue *int = ref.Value() *intValue = 127 // Store and retrieve that RefObject refObjectMap.rMap[1] = ref var refOut offheap.RefObject[int] = refObjectMap.rMap[1] fmt.Printf("Stored and retrieved %v", *(refOut.Value())) }
Output: Stored and retrieved 127
Example (RefSlice) ¶
Here we store and retrieve a RefSlice[byte] using a Reference typed container.
This example exists simply to illustrate how the Reference type can be used. I don't think it's obvious without at least one example.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { // The ReferenceMap type is capable of storing either RefString, // RefSlice or RefObject types type ReferenceMap[T any, R offheap.Reference[T]] struct { rMap map[int]R } // Here we instantiate a ReferenceMap which can store RefSlice references var refSliceMap ReferenceMap[byte, offheap.RefSlice[byte]] = ReferenceMap[byte, offheap.RefSlice[byte]]{ rMap: make(map[int]offheap.RefSlice[byte]), } // Create a RefSlice var store *offheap.Store = offheap.New() var ref offheap.RefSlice[byte] = offheap.ConcatSlices[byte](store, []byte("ref slice reference")) // Store and retrieve that RefSlice refSliceMap.rMap[1] = ref var refOut offheap.RefSlice[byte] = refSliceMap.rMap[1] fmt.Printf("Stored and retrieved %q", refOut.Value()) }
Output: Stored and retrieved "ref slice reference"
Example (RefString) ¶
Here we store and retrieve a RefString using a Reference typed container. We should note that instantiating a Reference type requires us to define a type for T. This type is unused because RefString, unlike RefObject and RefSlice, is not a parameterised type. This is awkward and inelegant, but survivable.
This example exists simply to illustrate how the Reference type can be used. I don't think it's obvious without at least one example.
package main import ( "fmt" "github.com/fmstephe/memorymanager/offheap" ) func main() { // The ReferenceMap type is capable of storing either RefString, // RefSlice or RefObject types type ReferenceMap[T any, R offheap.Reference[T]] struct { rMap map[int]R } // Here we instantiate a ReferenceMap which can store RefString references var refStringMap ReferenceMap[byte, offheap.RefString] = ReferenceMap[byte, offheap.RefString]{ rMap: make(map[int]offheap.RefString), } // Create a RefString var store *offheap.Store = offheap.New() var ref offheap.RefString = offheap.ConcatStrings(store, "ref string reference") // Store and retrieve that RefString refStringMap.rMap[1] = ref var refOut offheap.RefString = refStringMap.rMap[1] fmt.Printf("Stored and retrieved %q", refOut.Value()) }
Output: Stored and retrieved "ref string reference"
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
func New ¶
func New() *Store
Returns a new *Store.
This store manages allocation and freeing of any offheap allocated objects.
func NewSized ¶
Returns a new *Store.
The size of each slab, contiguous chunk of memory where allocations are organised, is set to be at least slabSize. If slabSize is not a power of two, then slabSize will be rounded up to the nearest power of two and then used.
Some users may have real need for a Store with a non-standard slab-size. But the motivating use of this function was to allow the creation of Stores with small slab sizes to allow faster tests with reduced memory usage. Most users will probably prefer to use the default New() above.
func (*Store) AllocConfigs ¶
func (s *Store) AllocConfigs() []pointerstore.AllocConfig
Returns the allocation config across all allocation size classes for this Store.
There are helper methods which allow the user to easily get the config for a single size class for object, slices and string allocations.
func (*Store) Destroy ¶
Releases the memory allocated by the Store back to the operating system. After this method is called the Store is completely unusable.
There may be some use-cases for this in real systems. But the motivating use case for this method was allowing us to release memory of Stores created in unit tests (we create a lot of them). Without this method the tests, especially the fuzz tests, would OOM very quickly. Right now I would expect that most (all?) Stores will live for the entire lifecycle of the program they are used in, so this method probably won't be used in most cases.
func (*Store) Stats ¶
func (s *Store) Stats() []pointerstore.Stats
Returns the statistics across all allocation size classes for this Store.
There are helper methods which allow the user to easily get the statistics for a single size class for object, slices and string allocations.