Next: objects memory segments, Up: objects memory [Index]
In this section we discuss some private C preprocessor symbols related to memory allocation and garbage collection concepts.
The preprocessor constant IK_MMAP_ALLOCATION_GRANULARITY
is
determined by the GNU Autotools’s configure
script and
defined in the automatically generated header file config.h. The
constants IK_PAGESIZE
and IK_PAGESHIFT
are hard–coded.
The constant IK_MMAP_ALLOCATION_GRANULARITY
represents the memory
allocation granularity used by mmap()
: no matter the number of
bytes we request to mmap()
, it will always allocate the smallest
multiple of the granularity that can contain the requested bytes:
|----------------------------| requested_size |-----------|-----------|-----------| allocated_size granularity granularity granularity
On some platforms the allocation granularity equals the system page size (example GNU+Linux), on other platforms it does not (example Cygwin). We assume the allocation granularity can be obtained on any platform with:
#include <unistd.h> long granularity = sysconf(_SC_PAGESIZE);
which should “officially” return the system page size, but in truth it does not (see Cygwin’s documentation).
To mind its own business, Vicare defines a “page size” as the
preprocessor symbol IK_PAGESIZE
, the number of bytes in
Vicare’s page size is:
4096 = 4 * 1024 = 4 * 2^10 = 2^12 = #x1000 = #b1000000000000
notice how many bits are set to zero in the binary representation of 4096:
(number->string 4096 2) ⇒ #b1000000000000 ;; 2109876543210
the constant 4096 is used often in the code, so the preprocessor
symbol IK_CHUNK_SIZE
is also defined to it.
Vicare’s page size is not defined to be equal to the system page size, but:
mmap()
returns pointers such that: the pointer
references the first byte of a system page, and so also the first byte
of a Vicare page; the numeric address of the pointer is an
exact multiple of 4096 (the 12 least significant bits are
zero).
It is natural to assign a zero–based index to each Vicare page:
page page page page page page |--------|--------|--------|--------|--------|--------| ^ ^ ^ ^ ^ ^ #x0000 #x1000 #x2000 #x3000 #x4000 #x5000 index 0 index 1 index 2 index 3 index 4 index 5
The preprocessor symbol IK_PAGESHIFT
is the number of bits to
right–shift a tagged or untagged pointer to obtain the index of the
page it is in; it is the number for which:
IK_PAGESIZE >> IK_PAGESHIFT = 1 2^IK_PAGESHIFT = IK_PAGESIZE
if IK_PAGESIZE
is 4096, the value of IK_PAGESHIFT
is 12; so for the example sizes 4000, 8000 and
10000 we have:
0 * 4096 <= 4000 < 1 * 4096 4000 >> 12 = 0 1 * 4096 <= 8000 < 2 * 4096 8000 >> 12 = 1 2 * 4096 <= 10000 < 3 * 4096 10000 >> 12 = 2
all the tagged pointers hold the tag in the 3 least significant
bits, so right–shifting by IK_PAGESHIFT
removes the tag:
right–shifting by IK_PAGESHIFT
works fine on both tagged and
untagged pointers.
Given the tagged or untagged pointer X: evaluate to the index of the memory page it is in; notice that the tag bits of a tagged pointer are not influent.
Given a number of bytes size: evaluate to the difference between two page indexes representing a region big enough to hold size bytes.
Given a Vicare page index idx: return an untagged pointer to the first word of the page.
Given a memory size in bytes: compute the smallest number of bytes
mmap()
will allocate to hold it.
Given a memory size in bytes: compute the smallest number of pages
of size IK_PAGESIZE
needed to hold it.
Given a number of Vicare pages: return the number of bytes
mmap()
allocates to hold them.
Given a pointer or tagged pointer X: return an untagged pointer referencing the first byte in the page right after the one X belongs to.
page page page |--------|--------|--------| ^ ^ X | returned_value
Given a pointer or tagged pointer X: return an untagged pointer referencing the first byte in the page X belongs to.
page page page |--------|--------|--------| ^ ^ | X returned_value
Next: objects memory segments, Up: objects memory [Index]