I've recently been fiddling with developing a custom allocator based on a memory pool, that is shared between multiple instances of the allocator.
The intention was that the allocator be compatible with STL and Standard C++ based containers such as vector, deque, map, string etc
However something in particular has caused me some confusion. Various implementations of the containers such as std::vector, std::string make use of Small Buffer Optimisation - stack based allocation for small initial memory requirements.
For example MSVC9.1 has the following member in the basic_string class:
union _Bxty
{ // storage for small buffer or pointer to larger one
_Elem _Buf[_BUF_SIZE];
_Elem *_Ptr;
char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;
I can't see how when instantiating such containers one can cajole
the implementation to only and always use the provided allocator
and not use SBO. I ask because one of intentions of implementing
custom allocators was to be able to use them in a shared memory
context, where the amount of the shared memory may be less than
the SBO limit some of the various implementations may use.
For example I would like to have a situation where I can have two
instances of std::string one per process sharing a common block
of memory which maybe smaller than or equal to the SBO upper
limit.
Possibly related: May std::vector make use of small buffer optimization?
typedef std::vector<int,mysharedmemallocator> shmvtype;
shmvtype v(2,0); //<-- if SBO then error as memory is allocated on
//stack not via the allocator
v[1] = 1234; //<-- if SBO then error as wrong piece of memory
// is being modified.
Lets look at another example that is not based on shared memory as it seems to over complicate things for some people. Lets say I want to specialize my std::basic_string or std::vector etc with an allocator that fills the memory it allocates with the value 0xAB prior to presenting the pointer back to the calling entity for no reason other than whimsy.
A container that is specialised with this new allocator, but that also uses SBO, will not have its SBO based memory filled with 0xAB pattern. So for example:
typedef std::basic_string<char,myfillmemallocator> stype
stype s;
s.resize(2);
assert(s[0] == 0xAB); // if SBO this will fail.
one of intentions of implementing custom allocators was to be able to use them in a shared memory context
This may be what you intend to do with it, but that's not why they exist. Indeed, with the exception of basic_string in C++98/03, it is not legal to share allocated memory between objects at all. They can share allocator objects, so they can get their memory from the same place. But it is illegal for modifications of one object to impact another that is unrelated; each instance must be separate.
Copy-on-write strings only work because the system assumes that any non-const access to a character will write to it, thus performing a copy. And in C++11, even basic_string is forbidden from doing copy-on-write-style stuff like this.
For example I would like to have a situation where I can have two instances of std::string one per process sharing a common block of memory which maybe smaller than or equal to the SBO upper limit.
That's not possible without writing your own class. The allocator only controls where the memory comes from. What you're wanting is a guaranteed copy-on-write string or some sort of shared string class.
What you want requires a container class specifically designed for this purpose.
Related
I have a class "DMRecSessionObj" which has two integer, a string and a vector as its data members.
class DMRecSessionObj
{
private:
int callNum;
int totCalls;
std::string sessionKey;
std::vector<DMRecord>RecList;
public:
...
};
After creating an object of DMRecSessionObj, the size of the vector RecList will be around 150000 when data is pushed into it according to requirement.
Several such DMRecSessionObj objects will be stored in a static map.
static std::map<string,DMRecSessionObj*> mapExpSessData;
So, I would like to know the better option of creating the DMRecSessionObj objects.
DMRecSessionObj* dmRec = new DMRecSessionObj(); //Dynamic memory allocation
DMRecSessionObj dmRecSessionObj; //Automatic memory allocation
The intention of asking this question is to understand the impacts that need to be taken care of in both these cases.
Dynamic Memory Allocation
Automatic memory allocation by compiler
Please suggest the better option considering the high memory requirements as the scenario.
Thanks in advance
As a rough rule of thumb, if you are using operator new directly, you should consider using standard containers (std::vector, std::map, etc) AND avoid use of raw pointers AND not use operator new directly.
As another rough rule of thumb, if you have a large memory usage (e.g. due to a large array or a large map) then, again, you should consider using resizeable standard containers (i.e. containers that can grow to accommodate more elements or a larger map) like std::vector and std::map, and not std::array (which has size set at compile time).
The reasons for those two rules of thumb are that the resizeable standard containers perform dynamic memory allocation, can resize themselves automatically (when you play by the rules when using them). Practically, a program can allocate more memory using dynamic memory allocation (which uses what is known, inaccurately, as "heap memory") than by using variables or objects of static or automatic memory duration (which uses what is known, inaccurately, as "stack memory" where there practically is less "stack memory" available to the program than "heap memory").
Given your description, if I was to use a static map, I'd change it to be;
static std::map<std::string,DMRecSessionObj> mapExpSessData; // note no pointer here
and then use a loop like this to populate it using code (which may, notionally, be in the body of a loop)
std::string string key = obtain_string_from_somewhere();
DMRecSessionObj object = read_object_from_somewhere();
mapExpSessData[key] = object;
This allows the map to take care of its own dynamic memory allocation. That way, if you need to manage the content of the map (e.g. remove entries or add entries) you can use operations that std::map provides for the purpose. Those operations, if you use them correctly, will generally clean up memory correctly (e.g. no leak due to you forgetting to release an object you have created manually with operator new, when you remove the entry from the map).
The objects key and object in the above are created automatically, which means they will cease to exist when the scope they are in completes. Technically, that MAY (not necessarily will) result in there being an additional object while you are populating the map). I suggest that additional object is insignificant if the map is large.
Note that, as a general rule, a program that needs a collection of 150000 objects (even small ones) can often be rationalised. If a program has 150000 objects in a map (or any container) then, practically, it often turns out that quite a small number of them are actually used by the program. It is therefore better to do some design effort to anticipate or estimate what objects actually are needed in memory, and therefore implement a smaller map or vector. That can involve trade-offs, such as needing to read infrequently used objects from storage rather than having them always in the map - but can significantly reduce memory usage of your program. And that can significantly improve performance in quite a few settings - such as where your program is running on a machine with limited resources, or is hosted by an operating system that is hosting other programs, and needs to periodically swap executing programs between memory and swap space (on disk) in order to ensure all programs get to run.
Bear in mind that using a static variable comes with significant penalties as well. If you do a search, you will find plenty of explanations of why static variables are often best avoided, and what the alternatives are.
Automatic memory allocation for an object occurs only for the members of the object as a POD.
For example, this class
class X
{
int p;
int* y;
};
has two members, the p and y and this will be allocated automatically. However, the memory that y will eventually point at (if at all) can be anywhere, in stack, in heap, or invalid. It's the class's business to manage its own memory, for which you have no control no matter where you create it.
A STL class like vector, manipulates the memory internally so you have the convenience of creating and managing it automatically. This seems that the class entire memory is automatically allocated, but it's not. But the implementation will create the memory at the best location, which is (99,999999%) the heap.
Some implementations keep a static allocation for low sizes (for example, std::string might have a char[5] to save an allocation when the string is only 4 bytes long). But you don't care.
I want to create a custom allocator for a multimap that will allocate the elements in shared memory.I came across boost.interprocess but found it quite complicated to implement.Is there any other workaround ?
I will not give here any implementation, rather to give you some directions.
If your shared memory abstraction or region, for example start at adress void* shMemAddr and if you decide that your stl container to use shared memory,
what needs to be done is to make container allocate memory starting at shMemAddr and further, until there is available memory to allocate in your shared pool. You can implement that using any allocation strategy, for example using malloc or placement new. Further, to be available for your container to use your allocator you need to provide your allocator as template argument, for multimap it would be multimap::allocator_type
class Alloc = allocator > as fourth template argument, after less as compare function,and, for example, if you store in your multimap pairs of int,double as key,value pairs, it would likely be something like this
multimap<int,double,less<int>,CustomAlloc<pair<int,double>>>
Now, your CustomAlloc allocator need to satisfies concept of Allocators which encapsulate specific lowlevel memory management, especially, if shared memory is resource to be allocate in, you need to arrange proper allocation of memory in a multithreaded enviornment. That means that, first, you need some structure for evidence of used memory. It can be some chained data structure, for example, and implementations like that is pretty common, so you need to keep invariants of that structure consistent. What that means is if your structure for book keeping of used(or free) memory need to be updated after succesfull allocation or deallocation it needs to be done atomicaly, so thread which possibly try to allocate memory see only structure in states before CustomAllocator allocation job is started or after allocation job is finished. For example, your first choice to do that could be using mutex to protect data, avoid races and keep invariants. This is just directions, and considering write your own allocators is not very hard, I hope this will help as good starting point.
I have been researching switching my allocation method from simpling overloading new to using multiple allocators through the code base. However, how can I efficiently use multiple allocators? The only way I could devise through my research was having the allocators be globals. Although, this seemed to have issues since it is typically a "bad idea" to have the use of many globals.
I am looking to find out how to use multiple allocators efficiently. For example, I may have one allocator use only for a particular subsystem, and a different allocator for a different subsystem. I am not sure if the only way to do this is through using multiple global allocators, so I am hoping for a better insight and design.
In C++2003 the allocator model is broken and there isn't really a proper solution. For C++2011 the allocator model was fixed and you can have per instance allocators which are propagated down to contained objects (unless, of course, you choose to replace them). Generally, for this to be useful you probably want to use a dynamically polymorphic allocator type which the default std::allocator<T> is not required to be (and generally I would expect it not to be dynamically polymorphic although this may be the better implementation choice). However, [nearly] all classes in the standard C++ library which do memory allocation are templates which take the allocator type as template argument (e.g. the IOStreams are an exception but generally they don't allocate any interesting amount of memory to warrant adding allocator support).
In several of your comments you are insisting that allocators effectively need to be global: that is definitely not correct. Each allocator-aware type stores a copy of the allocator given (at least, if it has any instance level data; if it doesn't there isn't anything to store as is e.g. the case with the default allocator using operator new() and operator delete()). This effectively means that the allocation mechanism given to an object needs to stick around as long as there is any active allocator using it. This can be done using a global object but it can also be done using e.g. reference counting or associating the allocator with an object containing all objects to which it is given. For example, if each "document" (think XML, Excel, Pages, whatever structure file) passes an allocator to its members, the allocator can live as member of the document and get destroyed when the document is destroyed after all its content is destroyed. This part of the allocator model should work with pre-C++2011 classes, as long as they take an allocator argument, as well. However, in pre-C++2011 classes the allocator won't be passed to contained objects. For example, if you give an allocator to a std::vector<std::string> the C++2011 version will create the std::strings using the allocator given to the std::vector<std::string> appropriately converted to deal with std::strings. This won't happen with pre-C++2011 allocators.
To actually use allocators in a subsystem you will effectively need to pass them around, either explicitly as an argument to your functions and/or classes or implicitly by way of allocator-aware objects which serve as a context. For example, if you use any of the standard containers as [part of] the context passed around, you can obtain the used allocator using its get_allocator() method.
You can use new placement. This can be used either to specify a memory region, or to overload the type's static void* operator new(ARGS). Globals are not required, and really a bad idea here, if efficiency is important and your problems are demanding. You would need to hold on to one or more allocators, of course.
The best thing you can do is understand your problems and create strategies for your allocators based on the patterns in your program and on actual usage. The general purpose malloc is very good at what it does, so always use that as one baseline to measure against. If you don't know your usage patterns, your allocator will likely be slower than malloc.
Also keep in mind that these types you use will lose compatability with standard containers, unless you use a global or thread local and custom allocator for standard containers -- which quickly defeats the purpose in many contexts. The alternative is to also write your own allocators and containers.
Some uses for multiple allocators include reduced CPU usage, reduced fragmentation, and fewer cache misses. So the solution really depends on what type and where your allocation bottleneck is.
CPU usage will be improved by having lockless heaps for active threads, eliminating synchronization. This can be done in your memory allocator with thread local storage.
Fragmentation will be improved by having allocations with different lifespans be allocated from different heaps -- allocating background IO in a separate heap from the users active task will ensure the two do not confound one another. This is likely done by having a stack for your heaps, and push/popping when you're in different functional scopes.
Cache misses will be improved by keeping allocations within a system together. Having Quadtree/Octree allocations come from their own heap will guarantee there is locality in view frustrum queries. This is best done by overloading operator new and operator delete for the specific classes (OctreeNode).
I was looking into how custom containers are created, such as eastl's container and several other models and I see that they all use an "allocator", much like std::vector does with std::allocator. Which got me thinking, why do new implementations of a vector container use an allocator when they typically have an underlying memory management override for new and delete?
Being able to replace operator new() and operator delete() (and their array versions) at program level may be sufficient for small program. If you have programs consisting of many millions lines of code, running many different threads this isn't at all suitable. You often want or even need better control. To make the use of custom allocators effective, you also need to be able to allocate subobjects using the same objects as the outer allocator.
For example, consider the use of memory arena to be used when answering a request in some sort of a server which is probably running multiple threads. Getting memory from operator new() is probably fairly expensive because it involves allocating a lock and finding a suitable chunk of memory in a heap which is getting more and more fragmented. To avoid this, you just want to allocate a few chunks of memory (ideally just one but you may not know the needed size in advance) and put all objects there. An allocator can do this. To do so, you need to inform all entities allocating memory about this chunk of memory, i.e. you need to pass the allocator to everything possibly allocating memory. If you allocate e.g. a std::vector<std::string, A> the std::string objects should know about the allocator: just telling the std::vector<std::string, A> where and how to allocate memory isn't enough to avoid most memory allocations: you also need to tell it to the std::string (well, actually the std::basic_string<char, std::char_traits<char>, B> for a suitable allocator type B which is related to A).
That is, if you really mean to take control of your memory allocations, you definitely want to pass allocators to everything which allocates memory. Using replaced versions of the global memory management facilities may help you but it is fairly constrained. If you just want to write a custom container and memory allocation isn't much of your concern you don't necessarily need to bother. In big systems which are running for extensive periods of time memory allocation is one of the many concerns, however.
Allocators are classes that define memory models to be used by Standard Library containers.
Every Standard Library container has its own default allocator, However the users of the container can provide their own allocators over the default.
This is for additional flexibility.
It ensures that users can provide their own allocator which provides an alternate form of memory management(eg: Memory Pools) apart from the regular heap.
If you want to produce a standard-compatible container then the answer is of course yes... allocators are described in the standard so they are required.
In my personal experience however allocators are not that useful... therefore if you are developing a container for a specific use to overcome some structural limitation of the standard containers then I'd suggest to forget about allocators unless you really see a reason for using them.
If instead you are developing a container just because you think you can do better than the standard vector then my guess is that you are wasting your time. I don't like the allocator idea design (dropping on the type something that shouldn't be there) but luckily enough they can be just ignored. The only annoyance with allocators when you don't need them (i.e. always) is probably some more confusion in error messages.. that however are a mess anyway.
Looking at vector, I realized that I have never used the second argument when creating vectors.
std::vector<int> myInts; // this is what I usually do
std::vector<int, ???> myOtherInts; // but is there a second argument there?
Looking at the link above it says that it is for:
Allocator object to be used instead of constructing a new one.
or, as for this one:
Allocator: Type of the allocator object used to define the storage allocation model. By default, the allocator class template for type T is used, which defines the simplest memory allocation model and is value-independent.
I guess it has to do with something with memory management. However, I am not sure how to use that.
Any pointers regarding this?
The default allocator, std::allocator<>, will handle all allocations made by std::vector<> (and others). It will make new allocations from the heap each time a new allocation is needed.
By providing a custom allocator, you can for instance allocate a big chunk of memory up front and then slice it up and hand out smaller pieces when separate allocations are needed. This will increase the allocation speed dramatically, which is good for example in games, at the cost of increased complexity as compared to the default allocator.
Some std type implementations have internal stack-based storage for small amounts of data. For instance, std::basic_string<> might use what is called a small string optimization, where only strings longer than some fixed length, say 16 characters (just an example!), gets an allocation from the allocator, otherwise an internal array is used.
Custom allocators are rarely used in general case. Some examples of where they can be useful:
Optimization for a specific pattern of allocations. For example, a concurrent program can pre-allocate a large chunk of memory via standard means at the beginning of task execution and then shave off pieces off it without blocking on the global heap mutex. When task is completed, entire memory block can be disposed of. To use this technique with STL containers, a custom allocator can be employed.
Embedded software, where a device has several ranges of memory with different properties (cached/noncached, fast/slow, volatile/persistent etc). A custom allocator can be used to place objects stored in an STL container in a specific memory region.
Maybe this will help: http://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c4079
You may try google for: stl allocator.
Allocators (STL) help you to manage memory for your objects in vector class. you may use the custom allocator for different memory model( etc).
Hi you can find example of custom allocator http://www.codeproject.com/KB/cpp/allocator.aspx