如何在不重新分配内存的情况下在 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...
}
我是 运行 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...
}