Parcourir la source

Added appropriate fonts for C names

Thomas Johnson il y a 6 mois
Parent
révision
1a2ddcbbf3
1 fichiers modifiés avec 83 ajouts et 11 suppressions
  1. 83
    11
      paper.tex

+ 83
- 11
paper.tex Voir le fichier

@@ -8,25 +8,97 @@
8 8
 
9 9
 \section{Introduction}
10 10
 
11
-When implementing the functionality of abstract data structures, it becomes necessary to have an array whose size is not known at compile time. This is problematic in languages like C and C++ where the size of an array must be known when compiling in order to calculate how bih the stack frame must be. The solution is to forgo having the array existing on the stack and not even dedicate space at compile time for the array. Instead, the array is created during runtime once the size of the array can be determined. This is known as dynamic memory allocation. A special region in a process's memory is dedicated for these kinds of allocations, called the heap, while a memory allocator keeps track of this space's usage. How the allocator handles memory that is no longer in use and situations in which a region must be resized depends on how it is implemented. In addition, the memory allocator has to balance how much memory that it uses for record keeping while also minimizing the amount of CPU cycles required to manage the memory region it has been given.
12
-
13
-In ANSI C, the standard library provides a memory allocator for general purpose use in programs. Dynamic memory allocation is performed through the malloc() library call in which the caller passes the desired size of the allocation and it returns a pointer to the allocated memory region. It must be noted that malloc does not initalize the returned memory region with any value, so the caller must initalize the array itself. However, the standard library also provides the calloc() library call in which the allocated memory is initalized with zero in every byte. Resizing of an allocation is performed using the realloc() and reallocarray() library calls, which will either grow the allocation in place or move the allocation to a space in which the new size can fit. The program must signify to the allocator that an memory region is to be marked free through the free() libary call. Should it fail to notify the allocator that an allocation is no longer in use before all of its references go out of scope, it will become impossible to access the underlying data or use the space it took up; a memory leak.
14
-
15
-Other languages' standard libraries can provide memory allocators or additional data structures for dynamic allocation using other techniques. Rather returning a pointer as a reference to the allocation, languages like C++ and Rust provide smart references that determines when the underlying memory allocation can be freed by detecting when all of its references have gone out of scope. Runtime languages like those running on the Java Virtual Machine or Microsoft's Common Language Interface also provide smart pointers, but wait to free the unused memory regions until a scheduled batch process occurs known as a garbage collection. Higher order languages like Python and Lua completely abstract away that dynamic allocation is occuring by only allowing abstract data structures to be created by the programmer, allowing for their implementation to handle the underlying allocations needed transparently. 
16
-
17
-In practice, abstract data structures do not allocate in the same way. It is possible to categorize them into two groups based on how they allocate. For data structures like vectors and smart strings, a single allocation is made at its creation and then resized as data is either added or removed. This is the first group. The second group consists of data structures like linked lists and trees, where many allocations and frees are requested, but each allocation is fixed in size. Rather than handling dynamic allocation request using one method, abstract data structures could instead give hints to the allocator as to what kind of allocations it should be making. Such an allocator could then be constructed to take advantage of these hints and optimize accordingly. This is what this paper aims to demonstrate. 
11
+When implementing the functionality of abstract data structures, it becomes necessary to have an array
12
+whose size is not known at compile time. This is problematic in languages like C and C++ where the
13
+size of an array must be known when compiling in order to calculate how bih the stack frame must be.
14
+The solution is to forgo having the array existing on the stack and not even dedicate space at compile
15
+time for the array. Instead, the array is created during runtime once the size of the array can be
16
+determined. This is known as dynamic memory allocation. A special region in a process's memory is
17
+dedicated for these kinds of allocations, called the heap, while a memory allocator keeps track of
18
+this space's usage. How the allocator handles memory that is no longer in use and situations in which
19
+a region must be resized depends on how it is implemented. In addition, the memory allocator has to
20
+balance how much memory that it uses for record keeping while also minimizing the amount of CPU cycles
21
+required to manage the memory region it has been given.
22
+
23
+In ANSI C, the standard library provides a memory allocator for general purpose use in programs.
24
+Dynamic memory allocation is performed through the {\tt malloc()} library call in which the caller
25
+passes the desired size of the allocation and it returns a pointer to the allocated memory region. It
26
+must be noted that malloc does not initalize the returned memory region with any value, so the caller
27
+must initalize the array itself. However, the standard library also provides the {\tt calloc()}
28
+library call in which the allocated memory is initalized with zero in every byte. Resizing of an
29
+allocation is performed using the {\tt realloc()} and {\tt reallocarray()} library calls, which will
30
+either grow the allocation in place or move the allocation to a space in which the new size can fit.
31
+The program must signify to the allocator that an memory region is to be marked free through the {\tt
32
+  free()} libary call. Should it fail to notify the allocator that an allocation is no longer in use
33
+  before all of its references go out of scope, it will become impossible to access the underlying
34
+  data or use the space it took up; a
35
+memory leak.
36
+
37
+Other languages' standard libraries can provide memory allocators or additional data structures for
38
+dynamic allocation using other techniques. Rather returning a pointer as a reference to the
39
+allocation, languages like C++ and Rust provide smart references that determines when the underlying
40
+memory allocation can be freed by detecting when all of its references have gone out of scope. Runtime
41
+languages like those running on the Java Virtual Machine or Microsoft's Common Language Interface also
42
+provide smart pointers, but wait to free the unused memory regions until a scheduled batch process
43
+occurs known as a garbage collection. Higher order languages like Python and Lua completely abstract
44
+away that dynamic allocation is occuring by only allowing abstract data structures to be created by
45
+the programmer, allowing for their implementation to handle the underlying allocations needed
46
+transparently. 
47
+
48
+In practice, abstract data structures do not allocate in the same way. It is possible to categorize
49
+them into two groups based on how they allocate. For data structures like vectors and smart strings, a
50
+single allocation is made at its creation and then resized as data is either added or removed. This is
51
+the first group. The second group consists of data structures like linked lists and trees, where many
52
+allocations and frees are requested, but each allocation is fixed in size. Rather than handling
53
+dynamic allocation request using one method, abstract data structures could instead give hints to the
54
+allocator as to what kind of allocations it should be making. Such an allocator could then be
55
+constructed to take advantage of these hints and optimize accordingly. This is what this paper aims to
56
+demonstrate. 
18 57
 
19 58
 \section{Implementation}
20 59
 
21 60
 \subsection{The Tree Allocator}
22 61
 
23
-Internally, the allocator is made of two self-balancing binary search trees in which one keeps records of free space available to the allocator while the other keeps records of allocated memory. Both trees are sorted using the size of their respective regions, though they can be search based on location in memory as well. Each node can be one of three types depending on their purpose. The type is used to determine which struct to represent the node with; the similar footprint permitting pointer polymorphism. A red-black tree was chosen to perform the self-balancing due to the minimal cost of adding a color field to each node. 
24
-
25
-To perform an allocation, the allocator first searches for within the free space tree for a memory block of suitable size. If it cannot find one, it requests the operating system for additional memory to mapped into the process before pushing the new space onto the tree and searching again. Once a node representing a memory region of sufficent size is found, it is removed from the free-space tree. The underlying space is then split to fit the new allocation and leave the excess space unallocated. The allocated space as a new node is pushed onto the allocations tree while the excess space also in new nodes are pushed back ono the free-space tree. In particular, the allocator attempts to place the new allocation in the center of the free space in order to minimize the chances of resizing causing a move. Deallocations are handled in a similar manner. When an address is requested to be freed, the allocator searches for the corresponding node in the allocations tree. This node is then popped off the allocations tree and pushed onto the free-space tree. In addition, if it is found that this node is surrounded by unallocated memory after being pushed onto the free-space tree, it will merge the nodes together. This keeps fragmentation at a minimum and speeds up subsequent allocations and deallocation. 
62
+Internally, the allocator is made of two self-balancing binary search trees in which one keeps records
63
+of free space available to the allocator while the other keeps records of allocated memory. Both trees
64
+are sorted using the size of their respective regions, though they can be search based on location in
65
+memory as well. Each node can be one of three types depending on their purpose. The type is used to
66
+determine which struct to represent the node with; the similar footprint permitting pointer
67
+polymorphism. A red-black tree was chosen to perform the self-balancing due to the minimal cost of
68
+adding a color field to each node. 
69
+
70
+To perform an allocation, the allocator first searches for within the free space tree for a memory
71
+block of suitable size. If it cannot find one, it requests the operating system for additional memory
72
+to mapped into the process before pushing the new space onto the tree and searching again. Once a node
73
+representing a memory region of sufficent size is found, it is removed from the free-space tree. The
74
+underlying space is then split to fit the new allocation and leave the excess space unallocated. The
75
+allocated space as a new node is pushed onto the allocations tree while the excess space also in new
76
+nodes are pushed back ono the free-space tree. In particular, the allocator attempts to place the new
77
+allocation in the center of the free space in order to minimize the chances of resizing causing a
78
+move. Deallocations are handled in a similar manner. When an address is requested to be freed, the
79
+allocator searches for the corresponding node in the allocations tree. This node is then popped off
80
+the allocations tree and pushed onto the free-space tree. In addition, if it is found that this node
81
+is surrounded by unallocated memory after being pushed onto the free-space tree, it will merge the
82
+nodes together. This keeps fragmentation at a minimum and speeds up subsequent allocations and
83
+deallocation. 
26 84
 
27 85
 \subsection{The Watermark Allocator}
28 86
 
29
-On its own, the watermark allocator present many problems that make is unfeasible to use as an allocator. This model of allocator is simply a stack that cannot have elements popped off of it while also holding a reference counter. The obvious problem with this is that frees ultimately are leaks under a watermark allocator. Unrestricted, a watermark allocator will eventually run out of memory even though free space may exist behind its stack pointer. This simplistic model does not come without its benefits; however, being that an allocation requires very little overhead and metadata to handle. The solution that was derived to take advantage of this property was to use the tree allocator to manage a series of finite sized watermark allocators. The implementation does not create an instance of a watermark allocator until a request for a fixed sized allocation is made. It is limited to a space of 4096 bytes, enforcing that the allocator be used for small, fixed size allocations. Larger allocations will either fail or be allocated using the tree allocator instead. Should an allocator run out of space, a new one is created and the allocation is performed on that new allocator. In addition, it is stored as a node within the tree allocator, meaning the last reference to the memory region will be the global allocator itself, which will free the space through the tree allocator automatically when the reference count on the space goes to zero. 
87
+On its own, the watermark allocator present many problems that make is unfeasible to use as an
88
+allocator. This model of allocator is simply a stack that cannot have elements popped off of it while
89
+also holding a reference counter. The obvious problem with this is that frees ultimately are leaks
90
+under a watermark allocator. Unrestricted, a watermark allocator will eventually run out of memory
91
+even though free space may exist behind its stack pointer. This simplistic model does not come without
92
+its benefits; however, being that an allocation requires very little overhead and metadata to handle.
93
+The solution that was derived to take advantage of this property was to use the tree allocator to
94
+manage a series of finite sized watermark allocators. The implementation does not create an instance
95
+of a watermark allocator until a request for a fixed sized allocation is made. It is limited to a
96
+space of 4096 bytes, enforcing that the allocator be used for small, fixed size allocations. Larger
97
+allocations will either fail or be allocated using the tree allocator instead. Should an allocator run
98
+out of space, a new one is created and the allocation is performed on that new allocator. In addition,
99
+    it is stored as a node within the tree allocator, meaning the last reference to the memory region
100
+    will be the global allocator itself, which will free the space through the tree allocator
101
+    automatically when the reference count on the space goes to zero. 
30 102
 
31 103
 \section{Results}
32 104
 

Chargement…
Annuler
Enregistrer