C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++对象池优化内存管理

C++利用对象池优化内存管理解决MISRA报警的代码详解

作者:mr.Darker

本篇详细讲解如何用对象池技术优化C++项目中的内存管理,彻底消除new/delete带来的MISRA报警,兼顾高性能与安全规范,需要的朋友可以参考下

1. 背景与问题起因

初始需求:

初始代码(示意):

IProcessor* CreateAoiProcessor() {
    return new CAoiProcessor();
}

void ReleaseProcessor(IProcessor* pProcessor) {
    delete pProcessor;
}

遇到的问题:

Rule A18-4-1:Dynamic heap memory allocation shall not be used.

风险点:

2. 初步尝试:对象池(ProcessorObjectPool)设计

基本思路:

优点:

缺点:

使用场景:

3. 二次优化:shared_ptr + 自定义删除器版本

核心思路:

  1. 对象池内部预分配完整对象,禁止动态分配
  2. 对外接口选择 std::shared_ptr,绑定自定义删除器
  3. 当用户释放对象时,并非 delete,而是将对象归还池内

优点:

缺点:

使用场景:

4. 解决过程中的 MISRA / AUTOSAR 报警问题记录

报警规则编号报警信息解决方案
A18-4-1禁止动态内存分配(禁止 new/delete)替换为对象池,固定数组预分配
M6-6-5函数必须只有一个出口统一 return,避免提前返回
M4-2-1if/else 必须成对补全 else 分支
命名规范成员变量必须加 m_ 前缀全部重命名为 m_xxx
OOP50-CPP构造/析构中不能调用虚函数移除析构中 Stop() 调用
M12-1-1构造/析构中禁止访问对象的动态类型(虚函数风险)构造函数内只做初始化,不调虚函数
命名规范static 成员必须加 s_ 前缀全部 static 变量改为 s_xxx

5. 整体优化成果

6. 最终对比总结

版本内存分配安全性易用性MISRA合规性
原版 new/delete动态堆分配容易泄漏简单但危险不合规
unique_ptr 对象池版静态预分配手动释放安全一般合规
shared_ptr 对象池版静态预分配自动回收最安全最易用合规

7. 建议总结

附录:完整示例代码(建议放文末)

ProcessorObjectPool.hpp

// unique_ptr 对象池版本源码
#pragma once

#include <stack>
#include <memory>
#include <mutex>

/**
 * @brief 通用的处理器对象池模板。
 * @tparam T 实际实现 IProcessor 的派生类。
 */
template <typename T>
class ProcessorObjectPool {
public:
    using Ptr = std::unique_ptr<T>;

    /**
     * @brief 获取一个处理器对象。
     * @return 智能指针,包装了一个 T 类型实例。
     */
    Ptr Acquire();

    /**
     * @brief 回收一个处理器对象。
     * @param pObj 要回收的对象(智能指针)。
     */
    void Release(Ptr pObj);

    /**
     * @brief 获取对象池的单例实例。
     * @return 静态的对象池实例。
     */
    static ProcessorObjectPool<T>& Instance();

private:
    ProcessorObjectPool() = default;
    ~ProcessorObjectPool() = default;

    ProcessorObjectPool(const ProcessorObjectPool&) = delete;
    ProcessorObjectPool& operator=(const ProcessorObjectPool&) = delete;

    std::stack<Ptr> m_pool;
    std::mutex m_mutex;
    static constexpr std::size_t MAX_POOL_SIZE = 64;  ///< 池中最大缓存对象数量
};

// 模板实现必须包含在头文件中
#include "ProcessorObjectPool.inl"

//============================================================================================
//============================================================================================

// shared_ptr 对象池版本源码
#pragma once

#include <array>
#include <memory>
#include <mutex>
#include <bitset>
#include <cstddef>

/**
 * @file ProcessorObjectPool.h
 * @brief 基于静态内存的对象池模板类,适配 MISRA / AUTOSAR C++。
 * @tparam T 对象类型(必须支持默认构造)。
 * @tparam N 对象池大小,最大可同时持有的对象数量。
 */
template <typename T, std::size_t N>
class ProcessorObjectPool {
public:
    /**
     * @brief 对象指针类型,使用 shared_ptr 包装,带自定义回收逻辑。
     */
    using Ptr = std::shared_ptr<T>;

    /**
     * @brief 获取对象池的单例实例。
     * @return 返回静态单例。
     */
    static ProcessorObjectPool& Instance();

    /**
     * @brief 获取一个可用对象指针。
     * @return 有效 shared_ptr,如果池已满返回空指针。
     */
    Ptr Acquire();

    /**
     * @brief 回收对象指针(由 shared_ptr 的 deleter 调用)。
     * @param pObj 需回收的对象指针。
     */
    void Recycle(T* pObj);

private:
    ProcessorObjectPool() = default;
    ~ProcessorObjectPool() = default;

    // 禁止复制与赋值
    ProcessorObjectPool(const ProcessorObjectPool&) = delete;
    ProcessorObjectPool& operator=(const ProcessorObjectPool&) = delete;

    std::array<T, N> m_objects;     ///< 静态分配的对象数组
    std::bitset<N> m_used{};        ///< 标记哪些对象已被占用
    std::mutex m_mutex;             ///< 互斥锁,保护并发访问
};

#include "ProcessorObjectPool.inl"  // 模板实现必须放头文件中

ProcessorObjectPool.inl

// 这里预留 unique_ptr 对象池版本实现
#pragma once

#include <utility>

template <typename T>
typename ProcessorObjectPool<T>::Ptr ProcessorObjectPool<T>::Acquire() {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (!m_pool.empty()) {
        Ptr obj = std::move(m_pool.top());
        m_pool.pop();
        return obj;
    } else {
        return std::unique_ptr<T>(new T());  // C++14 不能用 make_unique
    }
}

template <typename T>
void ProcessorObjectPool<T>::Release(Ptr pObj) {
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pool.size() < MAX_POOL_SIZE) {
        m_pool.push(std::move(pObj));
    } else {
        // 超出限制,自动释放,不入池
    }
}

template <typename T>
ProcessorObjectPool<T>& ProcessorObjectPool<T>::Instance() {
    static ProcessorObjectPool<T> instance;
    return instance;
}

//============================================================================================
//============================================================================================

// 这里预留 shared_ptr 对象池版本实现
#pragma once

/**
 * @brief 获取单例对象池实例。
 */
template <typename T, std::size_t N>
ProcessorObjectPool<T, N>& ProcessorObjectPool<T, N>::Instance()
{
    static ProcessorObjectPool<T, N> instance;
    return instance;
}

/**
 * @brief 获取一个可用对象的 shared_ptr。
 *        若池中存在未使用对象,则直接返回;
 *        若全部占用,则返回空 shared_ptr。
 */
template <typename T, std::size_t N>
typename ProcessorObjectPool<T, N>::Ptr ProcessorObjectPool<T, N>::Acquire()
{
    std::lock_guard<std::mutex> lock(m_mutex);

    T* pRaw = nullptr;
    for (std::size_t i = 0; i < N; ++i) {
        if (!m_used[i]) {
            m_used[i] = true;
            pRaw = &m_objects[i];
            break;
        }
    }

    Ptr result;
    if (pRaw != nullptr) {
        // 创建 shared_ptr,附带回收 deleter
        result = Ptr(pRaw, [](T* p) {
            ProcessorObjectPool<T, N>::Instance().Recycle(p);
        });
    }

    return result;
}

/**
 * @brief 回收一个对象指针回池中。
 * @param pObj 需释放的对象,必须为池中对象。
 */
template <typename T, std::size_t N>
void ProcessorObjectPool<T, N>::Recycle(T* pObj)
{
    if (nullptr == pObj) {
	    return;
    }

    std::lock_guard<std::mutex> lock(m_mutex);
    const std::ptrdiff_t nIndex = pObj - m_objects.data();
    if ((nIndex >= 0) && (static_cast<std::size_t>(nIndex) < N)) {
        m_used[static_cast<std::size_t>(nIndex)] = false;
        // 注意:对象不会析构。若对象含状态,应在 T 内部自行 reset()
        pObj->Reset();
    }
}

ProcessorFactory.cpp 旧新对比

// ProcessorFactory 旧源码
#include "pch.h"
#include "ProcessorFactory.h"

#include "AoiProcessor.h"
#include "ControllerProcessor.h"

extern "C" {
    IProcessor* CreateAoiProcessor() {
        return new CAoiProcessor();
    }

    IProcessor* CreateControllerProcessor() {
        return new CControllerProcessor();
    }

    void ReleaseProcessor(IProcessor* pProcessor) {
        if (pProcessor) {
            delete pProcessor;
        }
    }
}

//============================================================================================
//============================================================================================

// ProcessorFactory 新源码
#include "pch.h"
#include "ProcessorFactory.h"
#include "AoiProcessor.h"
#include "ControllerProcessor.h"
#include "ProcessorObjectPool.h"

// 使用静态池管理对象(不使用 new/delete)
using AoiProcessorPool = ProcessorObjectPool<CAoiProcessor, 32>;
using CtrlProcessorPool = ProcessorObjectPool<CControllerProcessor, 32>;

// 内部共享引用池,避免 shared_ptr 提前析构
static std::vector<std::shared_ptr<IProcessor>> s_processorRefs;
static std::mutex s_mutex;

extern "C" {
    IProcessor* CreateProcessor(int nType) {
        std::shared_ptr<IProcessor> sp;
        IProcessor* pRaw = nullptr;

        if (nType == 0) {
            sp = AoiProcessorPool::Instance().Acquire();
        }
        else if (nType == 1) {
            sp = CtrlProcessorPool::Instance().Acquire();
        }
        else {
            sp = nullptr;
		}

        if (sp) {
            pRaw = sp.get();
            std::lock_guard<std::mutex> lock(s_mutex);
            s_processorRefs.emplace_back(std::move(sp));
        }

        return pRaw;
    }

    void ReleaseProcessor(IProcessor* pProcessor) {
        if (pProcessor == nullptr) {
            return;
        }

        std::lock_guard<std::mutex> lock(s_mutex);
        auto it = std::remove_if(s_processorRefs.begin(), s_processorRefs.end(), [=](const std::shared_ptr<IProcessor>& ptr) {
        	return ptr.get() == pProcessor;
        });
        s_processorRefs.erase(it, s_processorRefs.end());
    }
}

以上就是C++利用对象池优化内存管理解决MISRA报警的代码详解的详细内容,更多关于C++对象池优化内存管理的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文