Boost::managed_mapped_file不能分配所有已增长的空间

boost::managed_mapped_file cannot allocate all of grown space

本文关键字:空间 不能分 mapped managed file 不能 Boost 分配      更新时间:2023-10-16

我试图增长一个内存映射文件,我成功地增长它,但我不能分配我所要求的所有额外空间-我只是得到一个std::bad_alloc代替。

下面是一个示例,显示了在Linux上使用g++的效果(我在MSVC上的"真实"代码中也看到了相同的效果):

#include <memory>
#include <sstream>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/random_generator.hpp>
namespace
{
using MMapManager = boost::interprocess::basic_managed_mapped_file<
    char,
    boost::interprocess::rbtree_best_fit<boost::interprocess::null_mutex_family,
                                         boost::interprocess::offset_ptr<void>,
                                         16u>,
    boost::interprocess::iset_index>;
using MMapAllocatorType = boost::interprocess::allocator<
    std::size_t,
    MMapManager::segment_manager>;
using MMapContainerType = boost::interprocess::vector<
    std::size_t,
    MMapAllocatorType>;
// I've measured this at 256 bytes for my example configuration, but it's not
// documented anywhere, so let's overcompensate
constexpr auto ManagedFileOverhead = 1024u;
boost::filesystem::path getTemporaryFilePath()
{
    auto ss = std::stringstream{};
    ss << "MMap_test_" << boost::uuids::random_generator{}();
    return boost::filesystem::temp_directory_path() / ss.str();
}
}
int main()
{
    // Create memory mapped file, initially for 100 items
    auto capacity = 100u;
    const auto size = (capacity * sizeof(std::size_t)) + ManagedFileOverhead;
    const auto path = getTemporaryFilePath();
    auto file = std::make_unique<MMapManager>(
        boost::interprocess::create_only,
        path.string().c_str(),
        size);
    auto data = file->construct<MMapContainerType>("data_")(file->get_segment_manager());
    // Fill with stuff
    data->reserve(capacity);
    for (auto i = 0u; i < capacity; ++i) {
        data->push_back(i);
    }
    // Let's grow to hold 162 items (100 * golden ratio)
    capacity = 162u;
    const auto newFileSize = (capacity * sizeof(std::size_t)) + ManagedFileOverhead;
    const auto oldFileSize = boost::filesystem::file_size(path);
    const auto extraBytes = newFileSize - oldFileSize;
    // Unmap from the process, and grow
    file.reset();
    MMapManager::grow(path.string().c_str(), extraBytes);
    // Reopen it to re-map it into this process
    file = std::make_unique<MMapManager>(
        boost::interprocess::open_only,
        path.string().c_str());
    data = file->find<MMapContainerType>("data_").first;
    // Allocate it all
    data->reserve(capacity); // Bang, you're dead
    // Close down
    file.reset();
    boost::system::error_code ec;
    boost::filesystem::remove(path, ec);
    return EXIT_SUCCESS;
}

将储备(增长后)设置为155项工作,只需多一个就会触发std::bad_alloc

为什么不工作?增长是否会在映射文件中产生额外的管理开销,导致我比预期更早地耗尽空间?

您对分配器的假设太多了。

映射文件的增长将在适当的位置发生。向量的增长不会。因此,虽然您只需要在之后增加保留大小的extraBytes ,但在保留期间,您需要足够的空间来容纳新旧分配。

通过使用:

证明
MMapManager::grow(path.string().c_str(), oldFileSize + extraBytes);

或者先清空旧容器:

{
    auto file = std::make_unique<MMapManager>(boost::interprocess::open_only, path.string().c_str());
    file->destroy<MMapContainerType>("data_");
    auto data = file->construct<MMapContainerType>("data_")(file->get_segment_manager());
}
MMapManager::grow(path.string().c_str(), extraBytes);