|
Allocation Library 1.00
An extreamly fast memory allocation Library.
|
First, NLD Allocator is Free to use for anyone for any purpose with the exception that NO ONE MAY redistribute the code, in part or in total, representing it as their work. Credit to Scott Lee, at NoLimitsDesigns.com MUST be given as well as notice of this license. This License is good for the current version of this Library which is currently 1.0. This does not preclude newer versions from holding a differnet license agreement; however, previous versions shall maintain their original license agreement.
Download the files.
Information on speed:
My only tests so far have been against TBB's scalable allocator and here are some results:
Allocations : 50
Allocation variance: 50 (i.e. random from size 1 to variance)
Speed Increase : 15% speed boost
Allocations : 1000
Allocation variance: 200 (i.e. random from size 1 to variance)
Speed Increase : 25% speed boost
Allocations : 500
Allocation variance: 500 (i.e. random from size 1 to variance)
Speed Increase : 35% speed boost
Allocations : 1000
Allocation variance: 1000 (i.e. random from size 1 to variance)
Speed Increase : 50% speed boost
Allocations : 1000
Allocation variance: 3000 (i.e. random from size 1 to variance)
Speed Increase : 270% speed boost
Allocations : 1000
Allocation variance: 3000 (i.e. random from size 1 to variance)
Speed Increase : 270% speed boost
Allocations : 1000
Allocation variance: 4000 (i.e. random from size 1 to variance)
Speed Increase : 350% speed boost
The speed continues to increase the larger the allocation sizes. . .
This is my first release. Currently, I have only had enough time to test a 32 bit and 64 bit build on Windows 7, compiled using Microsoft Visual Studio 2010. This allocator gains its speed from keeping a pool of memory allocated. You can set how much memory to hold in the pool before evictions start to occur by changing MEMORY_USED_BEFORE_EVICTIONS. Also, once evictions start to occur, the memory is relaesed to the OS once it has not been used by setting the TIME_BEFORE_EVICTION define.
The only two functions you should use are NLD_Allocator::NLD_malloc and NLD_Allocator::NLD_free. The other functions are internal functions only. If you decide to use just those two functions manually, they will work correctly, read on for how to overcome the global new and delete obsitcles. There are serveral #defines that can be tweaked
TIME_BEFORE_EVICTION is the time in miliseconds (i.e. 1000 = 1 second) before memory in the pool will be evicted. The evictions will only occur once the memory in the pool is greater than MEMORY_USED_BEFORE_EVICTIONS.
MEMORY_USED_BEFORE_EVICTIONS is the number of bytes that will be keep in the pool for future allocations. This number will be application specific.
SEARCH_SPREAD is the number of bins that are checked for evictions. The bins are checked in a round robin order. There are 21 total bins right now. So, for each deallocation, 4 other bins will be checked for memory to evict. The default value is probably fine, and could be set lower if more speed is needed on deallocations
USE_CUSTOM_ALIGNMENT comment this out if you dont want your memory aligned. The alignment will be on what the compiler gives minus 8 bytes because of my header. So, if your free returns memory on a 4 byte boundary, there wont be a difference, same for 8 byte. So, in most cases, this should be turned on.
ALIGN_MEM_TO is the number of bytes to align the memory address returned. This can also be used as padding or a cache aligned memory allocation scheme if numbers like 64 or 128 are used, which would guarantee each allocation is on a seperate cache line and thus would eliminate false sharing. This could be benificial for some applications, however a big memory waste
Other than that, you can chose to override the global new and delete; however it is in the TESTING PHASE!!!!!! You MUST be carefull with when allocations are preformed. For example, if you override the new and delete, then call either of those functions at the end of the programs life, errors can occur. What this means is if you have an object declared as a global, and it runs its deconstructor when the program is terminating (i.e. after main() returns), it calls its destructor, right? So, if declared globally, it will run its deconstructor possibly before the allocator library has destroyed itself, since the allocation library is also declared globally. This is due to the fact that this allocation library will destory itself eventually, and I have no way to ensure it destroys itself last. So, what could happen is, the allocation library could destroy itself, then another part of the program could call delete, and with the library gone, the call will be invalid. Having said that, overloading the new and delete is dangerous right now!!!!! If you do decide to override new and delete and get an unusual error, replace the calls to NLD_Allocator with the standard calls to malloc and free to see if that was the problem.
It is a bad idead to overload the new and delete, then put some code inside the function that may call new itself. For example, std::cout<<"Allocating "<<size<<std::endl; is a VERY BAD IDEAD. Since new is called within that line if code (you cant see it, but it is called on the number conversion to text happening, specifically, on <<size<<, and will result in infinite recursion, which is not good at all. The same goes for any code that is inside of a call to delete or new. i.e. Do not put any code inside NLD_Allocator::NLD_malloc or NLD_Allocator::NLD_free that may call new as the same result will occur --infinite recursion.
OVERRIDE THE GLOBALS AT YOUR OWN RISK. If you follow the above paragraphs advise, your program should function fine.
inline void* operator new(size_t size) throw (std::bad_alloc){ if(size==0) size=1; void *ptr = NLD_Allocator::NLD_malloc(size); //void *ptr = malloc(size); //uncomment this if you are receiving errors and believe them to be coming from this library. This will ensure the calls are not routed through this library if(ptr) return ptr; throw std::bad_alloc(); } inline void* operator new[](size_t size) throw (std::bad_alloc){ return operator new(size); } inline void* operator new(size_t size, const std::nothrow_t& ) throw(){ if(size==0) size=1; void *ptr = NLD_Allocator::NLD_malloc(size); //void *ptr = malloc(size); //uncomment this if you are receiving errors and believe them to be coming from this library. This will ensure the calls are not routed through this library if(ptr) return ptr; return NULL; } inline void* operator new[](size_t size, const std::nothrow_t& ) throw(){ return operator new(size, std::nothrow); } inline void operator delete (void* ptr) throw (){ //if(ptr!=0) free(ptr); //uncomment this if you are receiving errors and believe them to be coming from this library. This will ensure the calls are not routed through this library if(ptr!=0) NLD_Allocator::NLD_free(ptr); } inline void operator delete[] (void* ptr) throw (){ operator delete(ptr); } inline void operator delete (void* ptr, const std::nothrow_t& ) throw(){ //if(ptr!=0) free(ptr); //uncomment this if you are receiving errors and believe them to be coming from this library. This will ensure the calls are not routed through this library if(ptr!=0) NLD_Allocator::NLD_free(ptr); } inline void operator delete[] (void* ptr, const std::nothrow_t& ) throw(){ operator delete(ptr, std::nothrow); }
1.7.4