Skip to content

Object Allocation

Sukant Pal edited this page Mar 11, 2018 · 2 revisions

Currently, the kernel supports only one allocator for per-object allocation. It is the slab allocator.

Slab Allocator

The slab allocator works by allocating large slabs directly from the page-allocator. Size of slabs are fixed in the algorithm and presently it is 4KB per slab. Each slab contains a descriptor struct Slab at the very end of the page.

struct Slab
{
	LinkedListNode liLinker;
	STACK bufferStack;
	unsigned long colouringOffset;
	unsigned long freeCount;
};

struct ObjectInfo
{
	LinkedListNode liLinker;// Used for listing this, for pressurizing vmm
	const char *name;// Name of the object, used for debugging
	unsigned long rawSize;// Raw size of the object
	unsigned long colorScheme;// Current coloring scheme for the incoming slabs
	unsigned long align;// Alignment constraints for the object
	unsigned long bufferSize;// Size of the aligned-object buffer
	unsigned long bufferPerSlab;// No. of buffers that can fit into one slab
	unsigned long bufferMargin;// Leftover-space in a slab, after buffers
	void (*ctor) (Void *);// Object-constructor (not for C++, yet)
	void (*dtor) (Void *);// Object-destructor (not for C++, yet)
	unsigned long allocatedObjects;// No. of object that are in usage
	unsigned long freeCount;// No. of objects that are free in current pool
	unsigned long callCount;// No. of operation done on this type (not used)
	Slab *emptySlab;// Cache for a empty slab
	CircularList partialList;// List of partial slabs
	CircularList fullList;// List of complete slabs
	Spinlock lock;// Serialization lock
};

Objects must be atleast 2 words large on the machine. This is because the allocator stores linked-list nodes at the starting of each buffer in the slab. To do so atleast 2 words are required. The first object is linked to the slab descriptor by the Slab::bufferStack field.

Difference between a Buffer & Object

A object can be aligned in the allocator. For example, struct ObjectInfo is always allocated at a 64 byte margin for better cache performance. The arena of memory whose size is aligned & can contain the object is the buffer. As 'sizeof(ObjectInfo)' is about 70-80 bytes the buffer-size will be 128-bytes.

Constructors & Destructors for objects

Each object can be initialized by a special constructor functor. This must take only one argument - void *pointerToObject. It is like the default constructor in C++. Whenever a slab is allocated, all objects are initialized, which removes the need to construct objects at allocation time again and again. This assumes that the objects are returned to KDelete function in the original initialized state.

Whenever a slab is destroyed & unmapped, the destructor for all objects are called as to release resources. The constructor or destructor may also be NULL to specify no special requirement of initialization or finalization.

Note, that C++ constructors & destructors ARE NOT included in this. So that way C structs would be much better for critical code & memory-intensive operations.

Algorithm

The allocator maintains two lists of slabs - partial & full. In the partial list, only those slabs which have free objects in their bufferStack are kept. In the full list, only those slabs which are fully occupied are kept. The allocator also maintains a cache for a empty slab, which is totally free. Only one free slab is kept in cache and all others are destroyed.

Coloring - The allocator also shifts objects (like in Linux kernel) and maintains a `colorScheme' field.