如何在不重新分配内存的情况下在 RapidJSON 中重用堆栈分配器

How to reuse Stack Allocator in RapidJSON without reallocating memory

我是 运行 FreeRTOS 中的单线程系统,资源有限。

我已经为 RapidJSON 分配器预先分配了缓冲区:

char            valueBuffer[2048];
char            parseBuffer[1024];
rapidjson::MemoryPoolAllocator<FreeRTOSRapidJSONAllocator> valueAllocator (valueBuffer, sizeof(valueBuffer))
rapidjson::MemoryPoolAllocator<FreeRTOSRapidJSONAllocator> parseAllocator (parseBuffer, sizeof(parseBuffer));

我遇到的问题是,每次使用其中一个分配器时,其大小都会不断增加(并在必要时分配新内存),除非它们被清除。在分配器上调用 Clear() 的问题是当分配器下次调整大小时再次调用 Malloc,我想避免这种情况。

有没有办法简单地重用现有的预分配内存,例如将分配器的大小设置回零?

我通过创建自定义分配器解决了这个问题。本质上是 rapidjson::MemoryPoolAllocator 的副本,并添加了以下方法:

void Reset()
{
    chunkHead_->size = 0;
    chunkHead_->next = 0;
}

每次处理完最后一个解析的字符串时都应该调用它。

我需要做同样的事情,我想我会注意到阅读分配器代码似乎是一个替代方案:

虽然我再次创建一个字符缓冲区[2048],但我没有创建分配器并将其保留在旁边。

相反,我在需要时重新创建和删除分配器,而 re-using 内存块。通过阅读分配器的代码,我没有看到 Malloc,所以应该都在堆栈上,不是吗?

编辑 - 代码示例:

class MyClass
{
public: 
    myClass() : 
    _json_log_string_buffer(&_json_string_buffer_allocator, 
                            _json_buffer_size) {}

(...)
private:
    static constexpr int _json_buffer_size {4096};
    char _json_logger_buffer[_json_buffer_size];

    rapidjson::CrtAllocator _json_string_buffer_allocator;
    rapidjson::StringBuffer _json_log_string_buffer;
};

MyClass::log_to_json()
{
    rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> 
    json_logger_allocator {_json_logger_buffer, 
                           sizeof(_json_logger_buffer)};

    rapidjson::Document json_doc(&json_logger_allocator);

    auto& allocator = json_doc.GetAllocator();

    json_doc.SetObject();

    // using it:
    json_doc.AddMember("id", id(), allocator);
    json_doc.AddMember("KEY", "VALUE", 
    allocator);
    (...)

    // Here, monitoring the size of allocator, it never goes 
    // beyond the 4096 on repeat invocations.
    // If I had it as a member, only creating once, it would grow.
    std::cout << "JSON allocator size: " << allocator.Size() << 
    ", capacity: " << allocator.Capacity() << std::endl;


    // Bonus point: I'm also using a rapidjson::StringBuffer.
    // From a first read it doesn't seem to re-allocate.
    // It doesn't use a MemoryPoolAllocator so I cannot do the 
    // same for it as I did for rapidjson::Document.
    _json_log_string_buffer.Clear();

    rapidjson::Writer<rapidjson::StringBuffer> 
    writer(_json_log_string_buffer);

    json_doc.Accept(writer);
    auto as_string = _json_log_string_buffer.GetString();

    // Using string with logger...
}