Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How much memory should 'managed_shared_memory' allocate? (boost)

I'm looking for a definitive answer (if indeed one exists) on how much memory should be allocated when creating a static chunks of shared memory via boost::interprocess's managed_shared_memory. Even official examples seem to allocate arbitrarily large chunks of memory.

Consider the following structure:

// Example: simple struct with two 4-byte fields
struct Point2D {
  int x, y;
};

My initial reaction is that the necessary size would be 8 bytes, or sizeof(Point2D). This fails miserably when I attempt to construct an object, giving me seg-faults at runtime.

// BAD: 8 bytes is nowhere near enough memory allocated.
managed_shared_memory segment(create_only, "My shared memory", sizeof(Point2D));

What read/write operation is causing seg-faults? Stack operations? Temporarily allocations within segment.construct()? How much overhead is necessary when allocating shared memory?

By trial-and-error I found that multiplying the size by 4 can work for the above structure, but falls apart when I start adding more fields to my struct. So, that reeks of a bad hack.

Some might argue that "memory is cheap" in the modern PC, but I disagree with this philosophy and dislike allocating more than I need to, if I can avoid it. I dug around the Boost docs yesterday and couldn't find any recommendations. Here's to learning something new today!

like image 685
Courtney Christensen Avatar asked Nov 12 '10 16:11

Courtney Christensen


2 Answers

From this paragraph of the documentation :

The memory algorithm is an object that is placed in the first bytes of a shared memory/memory mapped file segment.

Layout of the memory segment :

 ____________ __________ ____________________________________________  
|            |          |                                            | 
|   memory   | reserved |  The memory algorithm will return portions | 
| algorithm  |          |  of the rest of the segment.               | 
|____________|__________|____________________________________________| 

The library has an extra memory overhead sitting at the beginning of the segment, thus occupying a few bytes of your requested size. According to this post and this post, this exact number of additional bytes cannot be determined :

You can't calculate it, because there are memory allocation bookeeping and fragmentation issues that change in runtime depending on your allocation/deallocation pattern. And shared memory is allocated by pages by the OS (4K on linux 64k on windows), so any allocation will be in practice allocated rounded to a page:

    managed_shared_memory segment(create_only, "name", 20);

will waste the same memory as:

    managed_shared_memory segment(create_only, "name", 4096);
like image 68
icecrime Avatar answered Oct 01 '22 01:10

icecrime


Something like using the OS'es memory page size works. In my case this works..

off_t size = sizeof(class1) + (sizeof(class2) * 3);
// round up to the OS page size.
long page_size = sysconf(_SC_PAGE_SIZE);
size = ((size / page_size) + (size % page_size ? 1 : 0)) * page_size;

Using boost::managed_shared_memory allows you to construct objects in the resulting space. Something like....

shared_memory_object::remove(m_name.c_str());
m_shared.reset(new managed_shared_memory(create_only, "myspace", size));
m_class1 = m_shared->construct<class1>("class1")();
m_class2 = m_shared->construct<class2>("class2")[3]();
like image 30
lprent Avatar answered Oct 01 '22 03:10

lprent