提高IPC Managed_memory_segment bad_alloc

时间:2019-01-18 14:56:14

标签: c++ boost ipc boost-interprocess

在尝试编写一段使用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运算符分别返回IPCStringstd::stringShmVector的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个字节没有足够的余地。

如果几天之内没有答案,我会将此编辑内容发布为答案。

2 个答案:

答案 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_";
}

如果有人认为我做错了,请发表评论。