【问题标题】:Vector of structs containing allocation pointers is failing to destruct包含分配指针的结构向量无法销毁
【发布时间】:2022-01-06 07:52:46
【问题描述】:

在我的项目中,我使用一个类进行分页内存分配。 这个类使用一个结构来存储它的所有分配:

enum PageStatus : uint_fast8_t {    //!< possible use stati of an allocated page
    PAGE_STATUS_INVALID     = 0b00,
    PAGE_STATUS_FREE        = 0b01, //!< the page is free
    PAGE_STATUS_USED        = 0b10, //!< the page is (partially) used
};

struct PhysicalPage {    //!< represents a page that has been allocated
    char* pData;         //!< pointer to the allocation
    PageStatus status;   //!< status of the allocation
};

这些PhysicalPages 存储在向量std::vector&lt;PhysicalPage&gt; physicalAllocations {}; 中。 在运行时页面被添加到向量中,一些可能会被删除。在删除过程中,最后一个元素被弹出并使用delete page.pData 返回内存。然而,当分配器类到达生命的尽头并从堆栈中释放时,就会出现问题。当pyhsicalAllocations 的向量析构函数被调用时,它不仅尝试破坏元素本身,还尝试破坏保留的内存(当大小更改时,向量保留作为缓冲区)。这会导致无效的内存指针被删除,从而停止程序执行:

double free or corruption (!prev)
Signal: SIGABRT (Aborted)

可能还值得一提的是,分配是在大于页面的块中完成的,这意味着每个 x 指针中只有一个实际上是有效的分配。所有其他指针只是与实际内存位置的偏移量。

为了防止错误发生,我尝试了:

手动删除(由于分块分配,这有点过于复杂)

for (size_t i = physicalAllocations.size(); 0 < i; i -= 1 << allocationChunkSize) {
    delete physicalAllocations[i - (1 << allocationChunkSize)].pData;
    for (size_t a = 0; a < 1 << allocationChunkSize; a++)
        physicalAllocations.pop_back();
}

清除向量

physicalAllocations.clear();

换一个清晰的矢量

std::vector<PhysicalPage>(0).swap(physicalAllocations);

其中没有一个有效。

我想承认,我已经在这个问题上工作了很长时间,非常感谢您的帮助。谢谢!

【问题讨论】:

  • std::shared_ptr&lt;char[]&gt; pData; 及其aliasing constructor (8) 可能会有所帮助。 (这甚至可能允许摆脱PageStatus)。
  • 我希望delete [],而不是delete。使用错误的表单会有未定义的行为。
  • delete 听起来像是罪魁祸首,但很难说。请提供 MWE / MRE。
  • @molbdnilo 你是对的,delete[] 是正确的形式。但是更改它并不能解决问题
  • @bitmask 正在处理它,完成后我会将它添加到原始问题中。

标签: c++ pointers memory vector free


【解决方案1】:

std::shared_ptr&lt;char[]&gt; pData 及其aliasing constructor (8) 可能会有所帮助。 (这甚至可能允许摆脱 PageStatus)。

它看起来像:

constexpr std::size_t page_size = 6;

struct PhysicalPage {
    std::shared_ptr<char[]> pData;
};

int main()
{
    std::vector<PhysicalPage> pages;
    {
        std::shared_ptr<char[]> big_alloc = std::unique_ptr<char[]>(new char[42]{"hello world. 4 8 15 16 23 42"});

        for (std::size_t i = 0; i != 42 / page_size; ++i) {
            pages.push_back(PhysicalPage{std::shared_ptr<char[]>{big_alloc, big_alloc.get() + i * page_size}});
        }
    }
    pages.erase(pages.begin());
    pages.erase(pages.begin() + 2);    
    for (auto& p : pages) {
        std::cout << std::string_view(p.pData.get(), page_size) << std::endl;
    }
}

Demo

【讨论】:

  • 现在测试更改......
  • 我测试了更改,除了内存查找时间比以前高 2 倍(可能是由于这是一个几乎没有优化的开发版本),它在尝试删除 non-valid 时仍然失败指针。这可能是我这边的一个实现错误,我稍后再尝试重新实现它。
  • 如果您提供 MCVE,我们可以查明错误。对错误代码进行基准测试毫无意义;-)
  • 谢谢!我现在开始工作了。查找地址的时间仍然从 8ns 增加到 19ns,但我相信这只是由于缺少优化。
猜你喜欢
  • 2018-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-30
  • 2021-12-26
  • 2023-04-10
  • 1970-01-01
相关资源
最近更新 更多