RapidJSON 自定义内存分配器详解与实战

前言

RapidJSON 是一个高性能的 C++ JSON 解析/生成库,其默认使用 MallocAllocator ------ 即直接调用 malloc/free 进行内存分配。在大多数场景下这完全够用。

但在高性能、低延迟、高并发或嵌入式环境中,频繁调用系统级 malloc/free 会带来:内存碎片化、分配/释放性能瓶颈、缓存不友好等问题

RapidJSON 从设计之初就支持 Allocator 模板参数,允许你"插拔"任意符合接口的内存管理器,真正做到"零成本抽象"。

一、标题rapidjson源码分析

cpp 复制代码
#define RAPIDJSON_DEFAULT_ALLOCATOR ::RAPIDJSON_NAMESPACE::MemoryPoolAllocator<::RAPIDJSON_NAMESPACE::CrtAllocator>
//...省略
template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR >
class GenericValue {
public:
    //! Name-value pair in an object.
    typedef GenericMember<Encoding, Allocator> Member;
    typedef Encoding EncodingType;                  //!< Encoding type from template parameter.
    typedef Allocator AllocatorType;                //!< Allocator type from template parameter.
    typedef typename Encoding::Ch Ch;               //!< Character type derived from Encoding.
    typedef GenericStringRef<Ch> StringRefType;     //!< Reference to a constant string
    typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator;  //!< Member iterator for iterating in object.
    typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator;  //!< Constant member iterator for iterating in object.
    typedef GenericValue* ValueIterator;            //!< Value iterator for iterating in array.
    typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of itself.
    typedef GenericArray<false, ValueType> Array;
    typedef GenericArray<true, ValueType> ConstArray;
    typedef GenericObject<false, ValueType> Object;
    typedef GenericObject<true, ValueType> ConstObject;
    ///...省略

通过rapidjson::GenericValue代码分析得出,GenericValue 是可以使用自定义的Allocator 分配器的,其默认为RAPIDJSON_DEFAULT_ALLOCATOR ,而这个宏又指向名为CrtAllocator的类

cpp 复制代码
#ifndef RAPIDJSON_MALLOC
///! customization point for global \c malloc
#define RAPIDJSON_MALLOC(size) std::malloc(size)
#endif
#ifndef RAPIDJSON_REALLOC
///! customization point for global \c realloc
#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size)
#endif
#ifndef RAPIDJSON_FREE
///! customization point for global \c free
#define RAPIDJSON_FREE(ptr) std::free(ptr)
#endif

//..........省略

//! C-runtime library allocator.
/*! This class is just wrapper for standard C library memory routines.
    \note implements Allocator concept
*/
class CrtAllocator {
public:
    static const bool kNeedFree = true;
    void* Malloc(size_t size) { 
        if (size) //  behavior of malloc(0) is implementation defined.
            return RAPIDJSON_MALLOC(size);
        else
            return NULL; // standardize to returning NULL.
    }
    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
        (void)originalSize;
        if (newSize == 0) {
            RAPIDJSON_FREE(originalPtr);
            return NULL;
        }
        return RAPIDJSON_REALLOC(originalPtr, newSize);
    }
    static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }

    bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
        return true;
    }
    bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
        return false;
    }
};

CrtAllocator类为C++申请内存的默认方式(malloc、realloc、free)

由此得出结论,仅需要自定义实现一个CrtAllocator类似的类,即可自定义rapidjson的内存分配器

cpp 复制代码
class MyAllocator {
public:
    static const bool kNeedFree = true; // 是否需要显式释放内存

    void* Malloc(size_t size);
    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
    void Free(void* ptr);
};

二、应用举例

1.以提高内存使用效率、减少碎片为目的

通过我的另外一篇文章QT基于mmap文件映射机制实现的内存池方法总结,实现自定义内存申请方式,即可将json数据映射到磁盘或其他储存中,减少内存的占用

2.性能分析、内存泄漏检测等场景

cpp 复制代码
class CrtAllocatorWithStats {
public:
    static const bool kNeedFree = true;

    size_t totalAllocated = 0;
    size_t totalFreed = 0;
    size_t peakUsage = 0;

    void* Malloc(size_t size) {
        void* ptr = std::malloc(size);
        if (ptr) {
            totalAllocated += size;
            peakUsage = std::max(peakUsage, totalAllocated - totalFreed);
        }
        return ptr;
    }

    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
        void* ptr = std::realloc(originalPtr, newSize);
        if (ptr) {
            if (newSize > originalSize) {
                totalAllocated += (newSize - originalSize);
            } else {
                totalFreed += (originalSize - newSize);
            }
            peakUsage = std::max(peakUsage, totalAllocated - totalFreed);
        }
        return ptr;
    }

    void Free(void* ptr) {
        if (ptr) {
            // 注意:无法知道释放了多少字节,除非记录分配表(略复杂)
            // 此处简化处理
            totalFreed += 1; // 仅计数次数
        }
        std::free(ptr);
    }
};

通过重写Allocator并在内存释放、申请等位置计数或计时,就能对此性能进行分析

三、总结

自定义内存分配器是 RapidJSON 高性能的"隐藏武器",它让你在内存控制、性能优化、场景适配上拥有极大的自由度。虽然大多数项目用默认分配器就够了,但在游戏、高频交易、嵌入式、服务端网关等场景,一个精心设计的 Allocator 能带来数倍性能提升和更低的延迟波动。
欢迎点赞、收藏、转发!

相关推荐
sycmancia1 天前
C++进阶01——示例
开发语言·c++
CoderCodingNo1 天前
【GESP】C++五级/四级练习题 luogu-P1413 坚果保龄球
开发语言·c++·算法
阿猿收手吧!1 天前
【C++】C++原子操作:compare_exchange_weak详解
java·jvm·c++
Trouvaille ~1 天前
【Linux】网络编程基础(二):数据封装与网络传输流程
linux·运维·服务器·网络·c++·tcp/ip·通信
2301_822366351 天前
C++中的命令模式变体
开发语言·c++·算法
每天要多喝水1 天前
nlohmann/json 的使用
c++·json
蓁蓁啊1 天前
C/C++编译链接全解析——gcc/g++与ld链接器使用误区
java·c语言·开发语言·c++·物联网
sheji34161 天前
【开题答辩全过程】以 基于SpringBoot的疗养院管理系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
短剑重铸之日1 天前
《设计模式》第六篇:装饰器模式
java·后端·设计模式·装饰器模式
D_evil__1 天前
【Effective Modern C++】第四章 智能指针:19. 对于共享资源使用共享指针
c++