对象池/内存分配器的依赖问题

在昨天写C++ Json解析库时遇到了很难找的Bug,利用对象池管理不同类型的对象,这些对象不是相互独立的而是互相依赖的。这就导致了在最后对象池执行析构时释放所有的对象出现了问题,具体如下。

  • Node类,是一个泛化的值,底层利用union/variant以实现可以容纳Json要求的所有类型的值,Number,Null,True,False,String,Array,Object等等。其中String,Array和Object时特殊的,其中含有指针用来指向分配好的对象,这就涉及到了析构。
  • String类,其中有char类型的指针指向用来保存字符串的内存,这些内存由一全局分配器分配(命名为:GlobalMemoryAllocator)。
  • Array类,其中存有Node的指针的数组,Node的空间由对象池(NodePool)分配并管理。
  • Object类,其中存的是ObjectMember的指针的数组,ObjectMember的空间由对象池(ObjectMemberPool)分配并管理。
  • ObjectMember类,其中有String作为对象属性的名字,有Node保存具体的属性的值,前面已经说过,String中有需要GlobalMemoryAllocator分配内存的部分,而Node中又有NodePool和ObjectMemberPool分配并管理内存的部分,这就造成了一定程度上的依赖。
创建对象时没问题
  • 创建对象需要GlobalMemoryAllocator、NodePool和ObjectMemberPool分配内存,只需在main函数最前面创建好各自的单例就好了。
析构对象时问题很大
  • 考虑下图场景
    例子

  • 我们没有手动利用对象池的API析构对象,当最后退出程序时,对象池的析构函数析构其中没有析构的对象,并最终释放所有内存。

  • 蓝色为NodePool管理,绿色为ObjectMemberPool管理,橙色为GlobalMemoryAllocator分配(不管理)

  • GlobalMemoryAllocator析构

  • ObjectMember执行析构,
    objectMember析构 --> node2释放 --> 字符串释放(–Crash–)

    • 当字符串释放时,全局内存分配器已经无效。
  • NodePool执行析构,node1析构 --> 析构objectMember(-- Crash --)

    • 因为ObjectMemberPool已经析构,无法为objectMember提供释放功能。
解决方法
  • 手动创建全局Pool/Allocator对象, 手动析构,确保按顺序析构,不能用单例常用的static变量来获得全局对象池/内存管理器,因为这些static对象的析构顺序不能被保证。
  • 正确的析构顺序是,
    NodePool --> ObjectMemberPool --> GlobalMemoryAllocator
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值