在尝试编写一段使用shared_memory_segment
以便写入“共享内存”的(便携式)C ++代码时,我多次遇到boost::interprocess::bad_alloc
。来自Boost documentation:
无法满足内存请求时抛出此异常。
因此,我必须分配的内存太少。下面是代码(仅用于编写,因为此处无关紧要):
shared_memory.h:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <string>
#include <exception>
namespace my_shared_memory
{
typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> IPCString;
typedef boost::interprocess::allocator<IPCString, boost::interprocess::managed_shared_memory::segment_manager> StringAllocator;
typedef boost::interprocess::vector<IPCString, StringAllocator> ShmVector;
bool write_to_memory(std::string wsuid, std::string loop_val, std::string should_intercept, std::string post_data) ;
const std::string shm_prefix = "shm_";
const std::string mutex_prefix = "mtx_";
}
shared_memory.cpp:
#include "shared_memory.h"
namespace apl_shared_memory
{
bool write_to_memory(std::string wsuid, std::string loop_val, std::string should_intercept, std::string post_data)
{
bool ret_val;
std::string shm_name = shm_prefix + wsuid;
std::string mtx_name = mutex_prefix + wsuid;
boost::interprocess::named_mutex named_mtx{boost::interprocess::open_or_create, mtx_name.c_str()};
size_t size = (sizeof(loop_val) + loop_val.size() + sizeof(should_intercept) + should_intercept.size() + sizeof post_data + post_data.size()) * 5;
try
{
named_mtx.lock();
boost::interprocess::shared_memory_object::remove(shm_name.c_str());
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, shm_name.c_str(), size);
CharAllocator charallocator (segment.get_segment_manager());
StringAllocator stringallocator(segment.get_segment_manager());
IPCString shm_loop_val(charallocator);
IPCString shm_should_intercept(charallocator);
IPCString shm_intercepted_data(charallocator);
shm_loop_val = loop_val.c_str();
shm_should_intercept = should_intercept.c_str();
shm_intercepted_data = post_data.c_str();
segment.destroy<ShmVector>("ShmVector");
ShmVector *shmVector = segment.construct<ShmVector>("ShmVector")(stringallocator);
shmVector->clear();
shmVector->push_back(shm_loop_val);
shmVector->push_back(shm_should_intercept);
shmVector->push_back(shm_intercepted_data);
named_mtx.unlock();
ret_val = true;
} catch(const std::exception& ex)
{
ret_val = false;
named_mtx.unlock();
boost::interprocess::shared_memory_object::remove(shm_name.c_str());
}
named_mtx.unlock();
return ret_val;
}
}
是的,我知道我不需要在所有三个地方进行unlock
通话。
问题似乎已经解决:
size_t size = (sizeof(loop_val) + loop_val.size() + sizeof(should_intercept) + should_intercept.size() + sizeof post_data + post_data.size()) * 5;
我认为添加时间5
是过大的,但事实并非如此。此代码在带有gcc 6.3.0的Debian 9和带有Microsoft Visual Studio 2015社区的Windows 10上可以正常使用。但是,在Xcode 10.1的MacOS上,当我尝试在向量中甚至插入第一个元素时,我都会得到boost::interprocess::bad_alloc
。该解决方案似乎将大小乘以10而不是5,但这似乎很浪费。
我添加了segment.get_free_memory
调用,并确定对于包含以下三个字符串(不带引号)的向量
“ true”“ true”“”
我需要512字节的Xcode。 sizeof
运算符分别返回IPCString
,std::string
和ShmVector
的32、24和32。因此,似乎我需要32+4
个字节用于一个“ true”字符串,32
用于空字符串。在此处添加ShmVector,我需要36+36+32+32=136
个字节来存储结构本身。我使用sizeof(std::string)
计算了大小,这里是24(疏忽),所以给了我(28+28+24)*5 = 400
,在这里还不够。
我的问题是如何确定段需要多少内存?要在调用该函数时知道要写入该段的数据,因此该数据的大小也是如此。 >
编辑:我将尺寸更改为:
size_t size = (sizeof(IPCString) + loop_val.size() + sizeof(IPCString) + should_intercept.size() + sizeof(IPCString) + post_data.size() + sizeof(ShmVector)) * 2 + 500;
到目前为止,太好了。写完该段后,我的可用空间总是少于500
个字节。我尝试了各种数据大小,范围从小于100字节到3兆字节。我尝试不乘以2
,但是在那种情况下,当我尝试插入大数据块时,程序崩溃,因为另外500
个字节没有足够的余地。
如果几天之内没有答案,我会将此编辑内容发布为答案。
答案 0 :(得分:0)
您正在对类型大小的等效性做许多假设。 ac字符串的内存使用情况与std :: string的内存使用情况不同,而std :: string的内存使用情况与实际上为vector的IPCString的内存使用情况不同,因此您对大小不感兴趣或长度,但容量。
根据需要调整组件大小:使用window.location.
hash: "#/core/enterpriseprofile"
host: "localhost:4200"
hostname: "localhost"
href: "http://localhost:4200/#/core/enterpriseprofile"
origin: "http://localhost:4200"
pathname: "/"
port: "4200"
protocol: "http:"
变量中的sizeof
而不是IPCString
变量,并且也使用std::string
而不是调整{{1 }}!
您应该更接近:
shm_loop_val.capacity() + shm_should_intercept.capacity() + shm_intercepted_data.capacity()
Boost实现也可能使您的数据对齐,但是我开始意识到这不太可能。看起来好像已经序列化了。我们可以调查您仍然有问题。
答案 1 :(得分:0)
经过研究和测试,我提出了以下解决方案。这里的关键点是使用boost::move
(或者也许是std :: move,不知道这里是否会有区别)。因为我们使用的是boost::move
,所以将没有IPCString
对象的副本,因此不需要乘以2
。请记住,由于我们定义IPCString
的方式,它将在共享内存段内分配。
增加的开销是必要的(可能是由于对齐或所添加的其他开销或两者兼而有之),但始终留有一些空间。因为我可能会发送几兆字节,所以500
字节的开销非常小。
我正在使用std::string
的{{1}}方法,因为它返回了the size of the string in bytes。
代码如下:
shared_memory.h:
size()
shared_memory.cpp:
#pragma once
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <string>
#include <vector>
#include <exception>
namespace apl_shared_memory
{
typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> IPCString;
typedef boost::interprocess::allocator<IPCString, boost::interprocess::managed_shared_memory::segment_manager> StringAllocator;
typedef boost::interprocess::vector<IPCString, StringAllocator> ShmVector;
bool write_to_memory(std::string wsuid, std::string loop_val, std::string should_intercept, std::string post_data) ;
const std::string shm_prefix = "shm_";
const std::string mutex_prefix = "mtx_";
}
如果有人认为我做错了,请发表评论。