Плохое размещение
Я получаю bad_alloc при попытке работать с общей управляемой памятью boost. Я скопировал пример поддержки из их краткого руководства для нетерпеливых и включил мои собственные изменения. Мой код приведен ниже, я прокомментировал пример и написал свой собственный ниже. Я также добавил кое-что для отладки и тестирования.
У кого-нибудь есть какие-либо идеи? Любая помощь очень ценится!
-М
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <functional>
#include <utility>
#include <iostream>
#include <string>
#define space_name "MySharedMemorydfgdfhgd"
namespace std{
}
int main ()
{
using namespace boost::interprocess;
//Remove shared memory on construction and destruction
struct shm_remove
{
shm_remove() { shared_memory_object::remove(space_name); }
~shm_remove(){ shared_memory_object::remove(space_name); }
} remover;
typedef int KeyType;
typedef boost::interprocess::managed_shared_memory::allocator<char>::type char_allocator;
//typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> char_allocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, char_allocator> shm_string;
struct certificateStorage{
int certificate_id;
certificateStorage( int _certificate_id, const char* _certificate, const char* _key, const char_allocator &al) :
certificate_id(_certificate_id)
{}
};
//Note that map<Key, MappedType>'s value_type is std::pair<const Key, MappedType>,
//so the allocator must allocate that pair.
//typedef std::pair<const int, float> ValueType;
typedef std::pair<const int, certificateStorage> certValueType;
//typedef allocator<ValueType, managed_shared_memory::segment_manager> ShmemAllocator;
typedef allocator<certValueType, boost::interprocess::managed_shared_memory::segment_manager> certShmemAllocator;
//typedef map<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> MyMap;
typedef map<KeyType, certificateStorage, std::less<KeyType>, certShmemAllocator> certSHMMap;
// typedef boost::interprocess::map<KeyType, int, std::less<KeyType>, certShmemAllocator> certSHMMap;
std::cout << "\n\n\nStarting the program.\n\n\n";
//Shared memory front-end that is able to construct objects
//associated with a c-string. Erase previous shared memory with the name
//to be used and create the memory segment at the specified address and initialize resources
const int numentries = 20;
const char* elementName = "mymap";
int size = sizeof(certificateStorage) * numentries + 1000;
std::cout << "SHM size is " <<size<< " bytes \n";
int runningsize = 0;
try{
//this stayed the same
managed_shared_memory shm_segment
(create_only
,space_name//segment name
,size);
certSHMMap *mymap;
//Initialize the shared memory STL-compatible allocator
//ShmemAllocator alloc_inst (segment.get_segment_manager());
certShmemAllocator alloc_inst (shm_segment.get_segment_manager());
char_allocator ca(shm_segment.get_allocator<char>());
for(int i = 0; i < numentries; i++){
try{
//MyMap *mymap =
// segment.construct<MyMap>("MyMap") //object name
//(std::less<int>() //first ctor parameter
// ,alloc_inst); //second ctor parameter
mymap = shm_segment.construct<certSHMMap>(elementName)
(std::less<int>()
,alloc_inst); //object name
}
catch(boost::interprocess::interprocess_exception &ex){
std::cout << "Certificates element already exists.";
try{
mymap = shm_segment.find<certSHMMap>(elementName).first; //object name
std::cout << " Fetching existing pointer.\n";
}
catch(boost::interprocess::interprocess_exception &ex){
std::cout << "\nCertificates object wont load\n";
mymap = shm_segment.find<certSHMMap>(elementName).first; //object name
}
}
certificateStorage thisCert(i, "", "", ca);
std::cout << "Created object.\n";
mymap->insert(certValueType(i, thisCert));
std::cout << "Inserted object. " << i <<" size is " <<sizeof(thisCert) << " \n";
runningsize += sizeof(thisCert) ;
std::cout << "SHM Current size is " << runningsize << " / " << size << "\n";
}
std::cout << "\n\nDone Inserting\nStarting output\n.";
/*
//Insert data in the map
for(int i = 0; i < 100; ++i){
mymap->insert(std::pair<const int, float>(i, (float)(i*i)));
}
for(int i = 0; i < 100; ++i){
std::cout << "Key: " << i << " Value: " << mymap->at(i) << "\n";
mymap->insert(std::pair<const int, float>(i, (float)(i*2)));
} */
for(int i = 0; i < numentries; i++){
try{
mymap = shm_segment.construct<certSHMMap>(elementName)(std::less<int>() ,alloc_inst); //object name
}
catch(boost::interprocess::interprocess_exception &ex){
std::cout << "Certificates element already exists.\n";
try{
mymap = shm_segment.find<certSHMMap>(elementName).first; //object name
}
catch(boost::interprocess::interprocess_exception &ex){
std::cout << "Certificates object wont load\n";
mymap = shm_segment.find<certSHMMap>(elementName).first; //object name
}
}
certificateStorage tmp = mymap->at(i);
std::cout << "The key is: " << i << " And the value is: " << tmp.certificate_id;
}
}
catch(boost::interprocess::interprocess_exception &ex){
std::cout << "\n shm space wont load wont load\n";
std::cout << "\n Why: " << ex.what() << "\n";
}
shared_memory_object::remove(space_name);
return 0;
}
И вот мой вывод программы...
Starting the program.
SHM size is 1080 bytes
Created object.
Inserted object. 0 size is 4
SHM Current size is 4 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 1 size is 4
SHM Current size is 8 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 2 size is 4
SHM Current size is 12 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 3 size is 4
SHM Current size is 16 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 4 size is 4
SHM Current size is 20 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 5 size is 4
SHM Current size is 24 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 6 size is 4
SHM Current size is 28 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 7 size is 4
SHM Current size is 32 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 8 size is 4
SHM Current size is 36 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 9 size is 4
SHM Current size is 40 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 10 size is 4
SHM Current size is 44 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 11 size is 4
SHM Current size is 48 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 12 size is 4
SHM Current size is 52 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 13 size is 4
SHM Current size is 56 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 14 size is 4
SHM Current size is 60 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
Inserted object. 15 size is 4
SHM Current size is 64 / 1080
Certificates element already exists. Fetching existing pointer.
Created object.
shm space wont load wont load
Why: boost::interprocess::bad_alloc
1 ответ
Кажется, у тебя просто не хватает памяти. Вы можете рассуждать, что не должны этого делать, так как отдельные распределения не занимают места.
Но фрагментация памяти может сделать это: если имеется достаточное "заполнение" или "накладные расходы" с объектами совместно используемой памяти, вы можете исчерпать непрерывно выделяемое пространство.
Либо сохраняйте свои данные в предварительно выделенном векторе (например), либо используйте один из более интеллектуальных алгоритмов распределения между процессами:
В данном случае самым простым способом решения этой проблемы, по-видимому, было бы просто сделать область разделяемой памяти в два раза больше (во всяком случае, на большинстве систем минимальный размер страницы памяти составляет 4 КБ).
Я просто использовал 2*size
и испытания подошли к завершению.
Обновление / исправление
Я только что проверил, что действительно делать вещи "векторным путем" гораздо эффективнее: заменять std::map
бустом flat_map
получает вам векторное хранилище.
Большая разница заключается в том, что каждый узел в карте выделяется динамически, что приводит к фиксированным издержкам и линейному потреблению доступной памяти.
наблюдения
- Существуют значительные начальные издержки, которые потребляют 320 байтов, прежде чем что-то случится
- с
flat_map
Вы также резервируете векторную емкость заранее, вы видите, что вы можете выиграть лишь немного больше эффективности хранения.
Приведенный выше график был создан на основе результатов следующей программы. Ищите звонки get_free_memory()
, Переключать map
реализация, просто изменить #if 0
в #if 1
, (Обратите внимание, как я очистил часть кода, который был ненужным повторением и использовал исключения для управления потоком).
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/flat_map.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <functional>
#include <utility>
#include <iostream>
#include <string>
#define space_name "MySharedMemory"
int main ()
{
using namespace boost::interprocess;
//Remove shared memory on construction and destruction
struct shm_remove
{
shm_remove() { shared_memory_object::remove(space_name); }
~shm_remove(){ shared_memory_object::remove(space_name); }
} remover;
typedef int KeyType;
typedef boost::interprocess::managed_shared_memory::allocator<char>::type char_allocator;
//typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> char_allocator;
//typedef boost::interprocess::basic_string<char, std::char_traits<char>, char_allocator> shm_string;
struct certificateStorage{
int certificate_id;
certificateStorage( int _certificate_id, const char* _certificate, const char* _key, const char_allocator &al) :
certificate_id(_certificate_id)
{}
};
#if 0 // STL
typedef std::pair<const int, certificateStorage> certValueType;
typedef allocator<certValueType, boost::interprocess::managed_shared_memory::segment_manager> certShmemAllocator;
typedef map<KeyType, certificateStorage, std::less<KeyType>, certShmemAllocator> certSHMMap;
#else // FLAT_MAP
typedef std::pair<int, certificateStorage> certValueType; // not const key for flat_map
typedef allocator<certValueType, boost::interprocess::managed_shared_memory::segment_manager> certShmemAllocator;
typedef boost::container::flat_map<KeyType, certificateStorage, std::less<KeyType>, certShmemAllocator> certSHMMap;
#endif
std::cout << "\n\n\nStarting the program.\n\n\n";
const int numentries = 20;
const char* elementName = "mymap";
int size = sizeof(certificateStorage) * numentries + 1000;
int runningsize = 0;
std::cout << "SHM size is " <<size<< " bytes \n";
try{
managed_shared_memory shm_segment(create_only, space_name/*segment name*/, size);
certShmemAllocator alloc_inst (shm_segment.get_segment_manager());
char_allocator ca(shm_segment.get_allocator<char>());
certSHMMap *mymap = shm_segment.find_or_construct<certSHMMap>(elementName)
(std::less<int>(), alloc_inst);
mymap->reserve(numentries);
for(int i = 0; i < numentries; i++){
std::cout << "Free memory: " << shm_segment.get_free_memory() << "\n";
certificateStorage thisCert(i, "", "", ca);
std::cout << "Created object.\n";
mymap->insert(certValueType(i, thisCert));
std::cout << "Inserted object. " << i <<" size is " <<sizeof(thisCert) << " \n";
runningsize += sizeof(thisCert) ;
std::cout << "SHM Current size is " << runningsize << " / " << size << "\n";
}
std::cout << "\n\nDone Inserting\nStarting output\n";
for(int i = 0; i < numentries; i++){
certificateStorage tmp = mymap->at(i);
std::cout << "The key is: " << i << " And the value is: " << tmp.certificate_id << "\n";
}
}
catch(boost::interprocess::interprocess_exception &ex){
std::cout << "\n shm space wont load wont load\n";
std::cout << "\n Why: " << ex.what() << "\n";
}
}