-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmemory_management.wil
236 lines (182 loc) · 5.66 KB
/
memory_management.wil
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/*
Wilfrid offers both manual and automatic memory management.
First, we will cover the manual way.
*/
fn manual_management_example()
{
/*
We can allocate structures on the stack or on the heap.
On the stack:
*/
let stack_thing : thing = {}
/*
On the heap:
*/
let heap_thing := new thing()
/*
To free heap-allocated variables we use 'delete':
*/
delete heap_thing
/*
Sometimes it's useful to allocate memory without a type.
We can use the 'allocate' function to get a specified
number of bytes. Memory obtained in this way
is always initialized to zero.
*/
let some_memory := allocate(1024)
/*
Sometimes it's useful to know a type's size. There are two
built-in functions for that: 'size_of' and 'size_of_type'.
'size_of' expects a variable instance, and 'size_of_type'
expects a type.
*/
printf("Size of a thing is %lld bytes\\n", size_of_type(thing))
let more_memory := allocate(size_of_type(thing) * 10)
let even_more_memory := allocate(size_of(more_memory))
delete some_memory
delete more_memory
delete even_more_memory
}
fn automatic_management_example()
{
/*
There is another way to allocate an object on the heap.
We can use the 'auto' keyword, which means that
we don't have to manually track the lifetime of an object.
*/
let managed_object = auto thing()
/*
Objects allocated with 'auto' are automatically deleted
when they are no longer referenced by any stored pointer.
This includes cases when the pointer is stored in an
object allocated with the 'new' keyword or on the stack.
You can freely mix 'auto' and 'new' objects and store
pointers cross-referencing them.
Since garbage collection can take time, the decision
of when to perform it is left to the language user.
We call the garbage collector using the 'gc' function:
*/
gc()
/*
We can query the managed memory state using
these functions:
*/
let count := query_gc_total_count()
let size := query_gc_total_memory()
printf("Current managed memory size: %llu\\n", size)
printf("Current managed object count: %llu\\n", count)
}
fn memory_arena_example()
{
/*
Wilfrid offers two additional memory management tools
out of the box: dynamic arrays and memory arenas.
Dynamic lists are covered in the "Dynamic lists" example.
Memory arenas are also called push buffers or linear
allocators. We allocate a contiguous block of memory,
and 'push' new structs to it. When no memory is left,
a new block is allocated.
Since the only system allocations are allocations
of entire blocks, memory arenas are usually much faster
than allocating objects individually. Also, deallocation
is much easier - we don't have to track each object,
we just have to call one function to deallocate
the whole arena.
Here is an example of how to use it:
*/
let block_size : ulong = 1024
let arena := allocate_memory_arena(block_size)
/*
Now we can push to the memory arena anything we want:
*/
for (let i := 0, i < 10, i++)
{
let size := size_of_type(thing) as ulong
let thing_ptr := arena.push(size) as thing^
printf("Address of a new thing: %p\\n", thing_ptr)
}
/*
We can use these functions to query
the memory arena's state:
*/
let total_size := arena.get_total_size()
let unused_size := arena.get_unused_size()
let used_size := arena.get_used_size()
printf("Total arena size: %llu\\n", total_size)
printf("Total allocations size: %llu\\n", used_size)
printf("Unused arena size: %llu\\n", unused_size)
/*
This function de-allocates all blocks:
*/
free_memory_arena(arena)
/*
Memory arena can be also used as a stack allocator.
We can use the 'push_arena_stack' function to mark
a beginning of a stack frame. Later, after we are
done with using objects allocated in the stack frame,
we can call the 'pop_arena_stack' function and clear
memory in the arena up to the beginning of that
stack frame.
Example:
*/
arena = allocate_memory_arena(block_size)
for (let i := 0, i < 10, i++)
{
arena.push(512)
}
printf("Total allocations size before the marker: %llu\\n",
arena.get_used_size())
let marker := arena.push_stack()
for (let i := 0, i < 10, i++)
{
arena.push(512)
}
printf("Total allocations size: %llu\\n",
arena.get_used_size())
/*
All allocations made after the marker
will be cleared when we call this function:
*/
arena.pop_stack(marker)
printf("Total allocations size after popping the stack: %llu\\n",
arena.get_used_size())
free_memory_arena(arena)
}
fn constructor_example()
{
/*
We can define custom constructors for objects.
For example, we construct this object by
passing two arguments to the 'new' expression:
*/
let new_thing = new thing(10, 12)
printf("The new thing's value is: %lld\\n", new_thing.value)
}
/*
To define a constructor, we declare a function with
the special 'constructor' name, returning the constructed
type. User-defined constructors must have at least
one argument.
*/
fn constructor (val_a: int, val_b: int) : thing^
{
/*
Constructors can call other constructors.
Here we call a default one, which just allocates memory
on the heap and initializes it to zero.
*/
let s := new thing()
s.value = val_a + val_b
return s
}
struct thing
{
value: long
}
fn main()
{
manual_management_example()
automatic_management_example()
memory_arena_example()
constructor_example()
}