Several classic allocator algorithms are based on having a single linear list of all free blocks of memory. (The list is often doubly-linked and/or circularly-linked.) Typically, sequential ts algorithms use Knuth's boundary tag technique, and a doubly- linked list to make coalescing simple and fast.
In considering sequential ts, it is probably most important to keep strategy and policy issues in mind. The classic linear-list implementations may notscale
well to large heaps, in terms of time costs as the num- ber of free blocks grows, the time to search the list may become unacceptable.56 More ecient and scal- able techniques are available, using totally or partially ordered trees, or segregated ts (see Section 3.6).57
Best t.A best t sequential ts allocator searches the free list to nd the smallest free block large enough to satisfy a request. The basic strategy here is to min- imize the amount of wasted space by ensuring that fragments are as smallas possible. This strategy might backre in practice, if the ts are too good, but not perfect|in that case, most of each block will be used, and the remainder will be quite small and perhaps unusable.58
In the general case, a best t search is exhaustive, although it may stop when a perfect t is found. This exhaustive search means that a sequential best t search does not scale well to large heaps with many free blocks. (Better implementations of the best t policy therefore generally use indexed ts or segrega- ted ts mechanisms, described later.)
Best t generally exhibits quite good memory usage (in studies using both synthetic and real traces). Var- ious scalable implementations have been built using balanced binary trees, self-adjusting trees, and segre- gated ts (discussed later).
The worst-case performance of best t is poor, with its memory usage proportional to the product of the amount of allocated data and the ratio between the largest and smallest object size (i.e., Mn) Rob77]. This appears not to happen in practice, or at least not commonly.
First t. First t simply searches the list from the be- ginning, and uses the rst free block large enough to 56This is notnecessarilytrue, of course, because the aver- age search time may be much lower than the worst case. For robustly good performance, however, it appears that simple linear lists should generally be avoided for large heaps.
57The confusion of mechanism with strategy and pol- icy has sometimes hampered experimental evaluations even after obviously scalable implementations had been discussed in the literature, later researchers often ex- cluded sequential t policies from consideration due to their apparent time costs.
58This potential accumulation of small fragments (often called \splinters" or \sawdust") was noted by Knuth Knu73], but it seems not to be a serious problem for best t, with either real or synthetic workloads.
satisfy the request. If the block is larger than neces- sary, it is split and the remainder is put on the free list.
A problem with sequential rst t is that the larger blocks near the beginning of the list tend to be split rst, and the remaining fragments result in having a lot of small blocks near the beginning of the list. These \splinters" can increase search times because many small free blocks accumulate, and the search must go past them each time a larger block is requested. Clas- sic (linear) rst t therefore may scale poorly to sys- tems in which many objects are allocated and many dierent-sized free blocks accumulate.
As with best t, however, more scalable implemen- tations of rst t are possible, using more sophisti- cated data structures. This is somewhat more dicult for rst t, however, because a rst t search must nd the rst block that is also large enough to hold the object being allocated. (These techniques will be discussed under the heading of Indexed Fits, in Sec- tion 3.8.)
This brings up an important policy question: what ordering is used so that the \rst" t can be found? When a block is freed, at what position is it inserted into the ordered set of free blocks? The most obvious ordering is probably to simply push the block onto the front of the free list. Recently-freed blocks would therefore be \rst," and tend to be reused quickly, in LIFO (last-in-rst-out) order. In that case, freeing is very fast but allocation requires a sequential search. Another possibility is to insert blocks in the list in address order, requiring list searches when blocks are freed, as well as when they are allocated.
An advantage of address-ordered rst t is that the address ordering encodes the adjacency of free blocks this information can be used to support fast coales- cing. No boundary tags or double linking (backpoint- ers) are necessary. This can decrease the minimum object size relative to other schemes.59
59 Another possible implementation of address-ordered rst t is to use a linked list ofallblocks, allocated or free, and use a size eld in the header of each block as a \relative" pointer (oset) to the beginning of the next block. This avoids the need to store a separate link eld, making the minimum object size quite small. (We've never seen this technique described, but would be sur- prised if it hasn't been used before, perhaps in some of the allocators described in KV85].) If used straight- forwardly, such a system is likely to scale verypoorly, because live blocks must be traversed during search, but this technique might be useful in combination with some
In experiments with both real and synthetic traces, it appears that address-ordered rst t may cause sig- nicantly less fragmentation than LIFO-ordered rst t (e.g., Wei76, WJNB95]) the address-ordered vari- ant is the most studied, and apparently the most used. Another alternative is to simply push freed blocks onto the rear of a (doubly-linked) list, opposite the end where searches begin. This results in a FIFO (rst-in-rst-out) queue-like pattern of memory use. This variant has not been considered in most stud- ies, but recent results suggest that it can work quite well|better than the LIFO ordering, and perhaps as well as address ordering WJNB95].
A rst t policy may tend over time toward behav- ing rather like best t, because blocks near the front of the list are split preferentially, and this may result in a roughly size-sorted list.60Whether this happens for real workloads is unknown.
Next t. A common\optimization"of rst t is to use a roving pointer for allocation Knu73]. The pointer records the position where the last search was satis- ed, and the next search begins from there. Successive searches cycle through the free list, so that searches do not always begin in the same place and result in an accumulation of splinters. The usual rationale for this is to decrease average search times when using a linear list, but this implementation technique has major ef- fects on the policy (and eective strategy) for memory reuse.
Since the roving pointer cycles through memory regularly, objects from dierent phases of program execution may become interspersed in memory. This may aect fragmentation if objects from dierent phases have dierent expected lifetimes. (It may also seriously aect locality. The roving pointer itself may have bad locality characteristics, since it examines each free block before touching the same block again. Worse, it may aect the localityof the program it allo- cates for, by scattering objects used by certain phases and intermingling them with objects used by other phases.)
In several experiments using both real traces WJNB95] and synthetic traces (e.g., Bay77, Wei76, Pag84, KV85]), next t has been shown to cause more
other indexing structure.
60This has also been observed by Ivor Page Pag82] in ran- domized simulations, and similar (but possibly weaker) observations were made by Knuth and Shore and others in the late 1960's and 1970's. (Section 4.)
fragmentation than best t or address-ordered rst t, and the LIFO-order variant may be signicantly worse than address order WJNB95].
As with the other sequential ts algorithms, scal- able implementations of next t are possible using various kinds of trees rather than linear lists.