You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: Chapters/01-memory.qmd
+15-20
Original file line number
Diff line number
Diff line change
@@ -57,7 +57,7 @@ Knowing the length (or the size) of each object is also important. So the length
57
57
in some cases, *known at compile time*.
58
58
59
59
The `zig` compiler cares more about knowing the length (or the size) of a particular object
60
-
, than to know it's actual value. But, if the `zig` compiler knows the value of the object, then, it
60
+
, than to know its actual value. But, if the `zig` compiler knows the value of the object, then, it
61
61
automatically knows the size of this object. Because it can simply calculate the
62
62
size of the object by looking at the size of the value.
63
63
@@ -84,7 +84,7 @@ but this array have a known fixed size, like `[60]u8` (which declares an array o
84
84
this type, or, this struct that you are declaring, becomes a type with a known fixed size at compile-time.
85
85
And because of that, in this case, the `zig` compiler do not need to known at compile-time the exact value of
86
86
any object of this type. Since the compiler can find the necessary size to store this object by
87
-
looking at the size of it's type.
87
+
looking at the size of its type.
88
88
89
89
90
90
Let's look at an example. In the source code below, we have two constant objects (`name` and `array`) declared.
@@ -118,14 +118,14 @@ For example, the function `input_length()` contains an argument named `input`, w
118
118
Is impossible to know at compile time the value of this particular argument. And it also is impossible to know the size/length
119
119
of this particular argument. Because it is an array that do not have a fixed size specified explicitly in the argument type annotation.
120
120
121
-
So, we know that this `input` argument will be an array of `u8` integers. But we do not know at compile-time, it's value, and neither his size.
121
+
So, we know that this `input` argument will be an array of `u8` integers. But we do not know at compile-time, its value, and neither his size.
122
122
This information is known only at runtime, which is the period of time when you program is executed.
123
123
As a consequence, the value of the expression `input.len` is also known only at runtime.
124
124
This is an intrinsic characteristic of any function. Just remember that the value of function arguments is usually not "compile-time known".
125
125
126
126
However, as I mentioned earlier, what really matters to the compiler is to know the size of the object
127
-
at compile-time, and not necessarily it's value. So, although we don't know the value of the object `n`, which is the result of the expression
128
-
`input.len`, at compile-time, we do know it's size. Because the expression `input.len` always return a value of type `usize`,
127
+
at compile-time, and not necessarily its value. So, although we don't know the value of the object `n`, which is the result of the expression
128
+
`input.len`, at compile-time, we do know its size. Because the expression `input.len` always return a value of type `usize`,
129
129
and the type `usize` have a known fixed size.
130
130
131
131
@@ -228,7 +228,7 @@ Because they will be automatically destroyed once the stack space is freed at th
228
228
So, once the function call returns (or ends, if you prefer to call it this way)
229
229
the space that was reserved in the stack is destroyed, and all of the objects that were in that space goes away with it.
230
230
This mechanism exists because this space, and the objects within it, are not necessary anymore,
231
-
since the function "finished it's business".
231
+
since the function "finished its business".
232
232
Using the `add()` function that we exposed above as an example, it means that the object `result` is automatically
233
233
destroyed once the function returns.
234
234
@@ -238,7 +238,7 @@ freed/destroyed at the end of the function scope.
238
238
:::
239
239
240
240
241
-
This same logic applies to any other special structure in Zig that have it's own scope by surrounding
241
+
This same logic applies to any other special structure in Zig that have its own scope by surrounding
242
242
it with curly braces (`{}`).
243
243
For loops, while loops, if else statements, etc. For example, if you declare any local
244
244
object in the scope of a for loop, this local object is accessible only within the scope
@@ -319,14 +319,14 @@ in the program.
319
319
If a local object in your function is stored in the stack, you should never
320
320
return a pointer to this local object from the function. Because
321
321
this pointer will always become undefined after the function returns, since the stack space of the function
322
-
is destroyed at the end of it's scope.
322
+
is destroyed at the end of its scope.
323
323
:::
324
324
325
325
But what if you really need to use this local object in some way after your function returns?
326
326
How can you do this? The answer is: "in the same you would do if this was a C or C++ program. By returning
327
327
an address to an object stored in the heap". The heap memory have a much more flexible lifecycle,
328
328
and allows you to get a valid pointer to a local object of a function that already returned
329
-
from it's scope.
329
+
from its scope.
330
330
331
331
332
332
### Heap {#sec-heap}
@@ -344,7 +344,7 @@ and that serves (or "deals with") any incoming request that reaches this particu
344
344
The heap is a good choice for this type of system, mainly because the server does not know upfront
345
345
how many requests it will receive from users, while it is active. It could be one single request,
346
346
or, 5 thousand requests, or, it could also be zero requests.
347
-
The server needs to have the ability to allocate and manage it's memory according to how many requests it receives.
347
+
The server needs to have the ability to allocate and manage its memory according to how many requests it receives.
348
348
349
349
Another key difference between the stack and the heap, is that the heap is a type
350
350
of memory that you, the programmer, have complete control over. This makes the heap a
@@ -379,13 +379,9 @@ In summary, the Zig compiler will use the following rules to decide where each
379
379
object you declare is stored:
380
380
381
381
1. every literal value (such as `"this is string"`, `10`, or `true`) is stored in the global data section.
382
-
383
382
1. every constant object (`const`) whose value **is known at compile-time** is also stored in the global data section.
384
-
385
383
1. every object (constant or not) whose length/size **is known at compile time** is stored in the stack space for the current scope.
386
-
387
384
1. if an object is created with the method `alloc()` or `create()` of an allocator object, this object is stored in the memory space used by this particular allocator object. Most of allocators available in Zig use the heap memory, so, this object is likely stored in the heap (`FixedBufferAllocator()` is an exception to that).
388
-
389
385
1. the heap can only be accessed through allocators. If your object was not created through the `alloc()` or `create()` methods of an allocator object, then, he is most certainly not an object stored in the heap.
390
386
391
387
@@ -400,13 +396,13 @@ source code of these operators, and find the memory allocation calls.
400
396
Many programmers find this behaviour annoying and hard to keep track of.
401
397
402
398
But, in Zig, if a function, an operator, or anything from the standard library
403
-
needs to allocate some memory during it's execution, then, this function/operator needs to receive (as input) an allocator
399
+
needs to allocate some memory during its execution, then, this function/operator needs to receive (as input) an allocator
404
400
provided by the user, to actually be able to allocate the memory it needs.
405
401
406
402
This creates a clear distinction between functions that "do not" from those that "actually do"
407
403
allocate memory. Just look at the arguments of this function.
408
-
If a function, or operator, have an allocator object as one of it's inputs/arguments, then, you know for
409
-
sure that this function/operator will allocate some memory during it's execution.
404
+
If a function, or operator, have an allocator object as one of its inputs/arguments, then, you know for
405
+
sure that this function/operator will allocate some memory during its execution.
410
406
411
407
An example is the `allocPrint()` function from the Zig standard library. With this function, you can
412
408
write a new string using format specifiers. So, this function is, for example, very similar to the function `sprintf()` in C.
@@ -464,8 +460,7 @@ known fixed length.
464
460
But in reality, there are two very common instances where this "fixed length limitation" of the stack is a deal braker:
465
461
466
462
1. the objects that you create inside your function might grow in size during the execution of the function.
467
-
468
-
2. sometimes, it is impossible to know upfront how many inputs you will receive, or how big this input will be.
463
+
1. sometimes, it is impossible to know upfront how many inputs you will receive, or how big this input will be.
469
464
470
465
Also, there is another instance where you might want to use an allocator, which is when you want to write a function that returns a pointer
471
466
to a local object. As I described at @sec-stack, you cannot do that if this local object is stored in the
@@ -499,7 +494,7 @@ allocators available in the standard library:
499
494
-`c_allocator()` (requires you to link to libc).
500
495
501
496
502
-
Each allocator have it's own perks and limitations. All allocators, except `FixedBufferAllocator()` and `ArenaAllocator()`,
497
+
Each allocator have its own perks and limitations. All allocators, except `FixedBufferAllocator()` and `ArenaAllocator()`,
503
498
are allocators that use the heap memory. So any memory that you allocate with
0 commit comments