5.1 subsystem initiation and Termination
Each subsystem in the game is dependent on each other and has a fixed sequence of startup and termination. It is defined as the main subsystem in the game engine.Singleton type(Singleton class) (usually calledManager). We define the start and end functions for each Singleton manager class to replace construction and destructor. This method also has other implementation methods, such as using a global priority queue to record various managers.
5.2 Memory Management
The efficiency of the software is also affected by the use of algorithms and memory. The memory has two impacts:Dynamic Memory AllocationAndMemory Access Mode.
1. Optimize dynamic memory allocation
The C ++ Global New/delete or malloc ()/Free () dynamically allocates memory, also knownHeap allocationSlow speed. Low efficiency is mainly caused by context switching between management overhead and management mode. An empirical rule in Game Development:Maintain a minimum heap allocation and never use heap allocation in a compact cycle.. The game engine cannot avoid using dynamic memory allocation, so most game engines implement one or more custom splitters. Customizes the allocation request of a distributor from the pre-allocated memory, and makes multiple assumptions about its usage mode to make it more efficient.
Stack distributor(Stack Allocator): Use malloc (), Global New, or declare a global byte array to arrange a pointer to the top of the stack. The memory below the pointer is allocated, the above is unallocated. For each allocation request, you only need to move the pointer up the number of bytes required for the request; release the last allocated memory block and move the pointer down to the corresponding number of bytes. Another implementation is the double-end stack distributor.
Pool distributorPool Allocator: used to allocate a large number of small pieces of memory of the same size, such as matrices, iterators, nodes in the linked list, and rendered grid instances. The pool distributor allocates a large block of memory in advance, which is a multiple of the allocation elements. Each element in the pool is added to a linked list that stores free elements. When receiving the allocation request, the pool distributor extracts the next element of the Free linked list and returns the element. When releasing an element, it only needs to insert the element into the free linked list, the time complexity of the allocation and release operations is O (1 ).
Alignment dispenser: If you want to allocate byte alignment, you only need to allocate a little more memory when allocating the memory. Then, you can adjust it to the alignment of the memory address and return the adjusted address. (Byte alignment is used for CPU efficient read operations ).
The offset calculation method is as follows: first, use the mask (mask) to retrieve the minimum valid bits of the original memory block address, and then subtract the expected alignment from this value. The expected offset is adjusted. The mask is equal to the number of aligned bytes minus 1. For example, if a 16-byte alignment memory block is requested, the mask is 15. If the original allocated memory block address is 0x00001233, perform the & operation with 0x0000000f to get 3, (16-3) = 13, 13 is the offset, add the original address to 13 to get the final alignment memory address 0x00001240.
When the memory is released, in order to get the address before adjustment to release the originally allocated memory, we store some metadata in the extra allocated memory, and store the offset in the byte before the adjusted address, finally, when the memory is released, the allocated address before adjustment can be obtained through simple computing.
Single Frame and Double Buffer Memory distributor: Used to allocate memory for temporary data in the game loop.
Single Frame splitter: reserve a piece of memory for Stack distributor management. At the beginning of each frame, reset the top pointer to the bottom address of the memory block.
Dual-buffer splitter: allows the memory block allocated in the I frame to be used for the I + 1 frame. The implementation method is to create two single-frame stack splitters of the same size, which are used alternately at each frame. The result of the previous loop can be retained.
Chapter 5 game Support System