一个简单的C++内存管理与引用计数指针
来源:互联网 发布:仓库货物记账软件 编辑:程序博客网 时间:2024/05/01 20:38
最近项目需要一些模式相对固定的内存申请和销毁,手痒写了个C++内存管理器和引用计数的智能指针,加入了一些多线程保护机制(未测试)。代码见文章后半部分。
在main()里做了一个简单速度测试。在我的i5 4590+8G+win7机器上,使用定制内存管理的程序耗时0.35秒,使用new/delete的耗时16.9秒。这个内存管理代码还可以根据堆上内存的申请和销毁模式做进一步定制。
MemManagement.h
#ifndef __MEMORY_MANAGEMENT_H_INCLUDED__#define __MEMORY_MANAGEMENT_H_INCLUDED__#include <mutex>#include <atomic>#include <iostream>// "Recreationally" created by pkathlon, 2017/06/25// Feel free to use, modify, and restructure itnamespace Customized_MemoryManagement {template <typename T>class FixedAllocatedMem {public:FixedAllocatedMem() {m_pSegHeader = nullptr;}FixedAllocatedMem(unsigned int nBlocks, unsigned int nElementsPerBlock) {if (nBlocks == 0 || nElementsPerBlock == 0) {return;}MemSegInfo *pPrevSeg;for (int i = 0; i < nBlocks; ++i) {MemSegInfo *newInfo = new MemSegInfo;newInfo->_ptr = new T[nElementsPerBlock];newInfo->_sz = nElementsPerBlock;newInfo->_state = 0x01;newInfo->_pNext = nullptr;if (i == 0) {m_pSegHeader = newInfo;}else {pPrevSeg->_pNext = newInfo;}pPrevSeg = newInfo;}}~FixedAllocatedMem() {ReleaseMem();if (m_pSegHeader != nullptr) {throw "Not all memory is returned at destructor!";}}T* AllocateMem(unsigned int nElements) {std::lock_guard<std::mutex> lock(m_Mutex);// this NAIVE strategy (N required, N newed)// by PKATHLON can be easily improved// with pre-allocation or other techniquesif (m_pSegHeader == nullptr) {m_pSegHeader = new MemSegInfo;m_pSegHeader->_ptr = new T[nElements];m_pSegHeader->_sz = nElements;m_pSegHeader->_state = 0x03;m_pSegHeader->_pNext = nullptr;return m_pSegHeader->_ptr;}MemSegInfo *pPrevSeg = nullptr;for (MemSegInfo *pMSI = m_pSegHeader; pMSI; pPrevSeg = pMSI, pMSI = pMSI->_pNext) {if ((pMSI->_state & 0x02) || pMSI->_sz < nElements) {continue; // occupied or insufficient size}if (pMSI->_sz > nElements) { // splitMemSegInfo *newInfo = new MemSegInfo;newInfo->_ptr = pMSI->_ptr + nElements;newInfo->_sz = pMSI->_sz - nElements;newInfo->_state = 0x00;newInfo->_pNext = pMSI->_pNext;pMSI->_sz = nElements;pMSI->_pNext = newInfo;}pMSI->_state |= 0x02;return pMSI->_ptr;}// append a new segMemSegInfo *newInfo = new MemSegInfo;newInfo->_ptr = new T[nElements];newInfo->_sz = nElements;newInfo->_state = 0x03;newInfo->_pNext = nullptr;pPrevSeg->_pNext = newInfo;return newInfo->_ptr;}bool ReturnMem(T *memPtr) {std::lock_guard<std::mutex> lock(m_Mutex); // PKATHLON is definitely an RAII-enthusiast!MemSegInfo *pPrevSeg = nullptr;for (MemSegInfo *pMSI = m_pSegHeader; pMSI; pPrevSeg = pMSI, pMSI = pMSI->_pNext) {if (memPtr == pMSI->_ptr) {/*if ((pMSI->_state & 0x02) == 0) {// try to return non-occupied memory}*/pMSI->_state &= 0xffffffd;MemSegInfo *pMergedPtr = pMSI;if ((pPrevSeg != nullptr) && (pPrevSeg->_state & 0x02) == 0 && (pMSI->_state & 0x01) == 0) {// cur seg available to be merged into the prev segpPrevSeg->_sz += pMSI->_sz;pPrevSeg->_pNext = pMSI->_pNext;pMergedPtr = pPrevSeg;}if (pMSI->_pNext != nullptr && pMSI->_pNext->_state == 0) {// next seg available to be mergedpMergedPtr->_sz += pMSI->_pNext->_sz;MemSegInfo *pMergedNext = pMSI->_pNext;pMergedPtr->_pNext = pMSI->_pNext->_pNext;delete pMergedNext;}if (pMergedPtr != pMSI) {delete pMSI; // PKATHLON thinks there may be more involved (but more efficient)// way to deal with these little elements in a linked list}return true;}}return false; // incorrect memPtr}void ReleaseMem() {std::lock_guard<std::mutex> lock(m_Mutex);// only block heads can be actually "released" (returned to OS)// and delete[] pInTheMiddle can cause serious problemsif (m_pSegHeader == nullptr) {return;}while (m_pSegHeader->_state == 0x01) {if (m_pSegHeader->_pNext == nullptr|| (m_pSegHeader->_pNext->_state & 0x01)) {delete[] m_pSegHeader->_ptr;MemSegInfo *pn = m_pSegHeader->_pNext;delete m_pSegHeader;m_pSegHeader = pn;if (pn == nullptr) {return;}}else {break;}}MemSegInfo *pPrevSeg = m_pSegHeader;for (MemSegInfo *pCurSeg = m_pSegHeader->_pNext; pCurSeg;pPrevSeg = pCurSeg, pCurSeg = pCurSeg->_pNext) {if (pCurSeg->_state != 0x01) {continue;}if (pCurSeg->_pNext == nullptr|| (pCurSeg->_pNext->_state & 0x01)) {delete[] pCurSeg->_ptr;MemSegInfo *pn = pCurSeg->_pNext;delete pCurSeg;pPrevSeg->_pNext = pn;pCurSeg = pPrevSeg;}}}void _displayChainedMemorySegments() const {// a tool for testingstd::cout << "\nChained Memory:\n";if (m_pSegHeader == nullptr) {std::cout << "No available memory block!\n";}int cnt = 0;for (MemSegInfo *pSeg = m_pSegHeader; pSeg != nullptr; pSeg = pSeg->_pNext, ++cnt) {std::cout << "Seg. No." << cnt << ", size = " << pSeg->_sz <<", occupied=" << (bool)(pSeg->_state & 0x02)<< ", blockHead=" << (bool)(pSeg->_state & 0x01) << std::endl;}}protected:struct MemSegInfo {T *_ptr;unsigned int _sz;int _state; // bit 0 - if it's a block head, bit 1 - if it's occupiedMemSegInfo *_pNext;}; // memory blocks are recorded in linked chainsMemSegInfo *m_pSegHeader;std::mutex m_Mutex;};template <typename T>class MemPointer {public:MemPointer() {m_pRefInfo = nullptr;}MemPointer(T *pMemWeWillNOTRelease) {m_pRefInfo = g_RefS_MemMgt.AllocateMem(1);m_pRefInfo->_bResponsible = false;m_pRefInfo->_pData = pMemWeWillNOTRelease;}MemPointer(MemPointer &oriMP) {if (++(oriMP.m_pRefInfo->_nRefCnt) == 1) {m_pRefInfo = nullptr;}else {m_pRefInfo = oriMP.m_pRefInfo;}}MemPointer(unsigned int nElementSize) {m_pRefInfo = g_RefS_MemMgt.AllocateMem(1);m_pRefInfo->_bResponsible = true;m_pRefInfo->_size = nElementSize;m_pRefInfo->_nRefCnt = 1;m_pRefInfo->_pData = g_Data_MemMgt.AllocateMem(nElementSize);}MemPointer& operator= (MemPointer &oriMP) {refStruct *dstRefStruct;if (++(oriMP.m_pRefInfo->_nRefCnt) == 1) {dstRefStruct = nullptr;}else {dstRefStruct = oriMP.m_pRefInfo;}if (this->m_pRefInfo && this->m_pRefInfo->_bResponsible) {if (--(this->m_pRefInfo->_nRefCnt) == 0) {g_Data_MemMgt.ReturnMem(this->m_pRefInfo->_pData);g_RefS_MemMgt.ReturnMem(this->m_pRefInfo);}}this->m_pRefInfo = dstRefStruct;return (*this);}MemPointer& operator= (T *pMemWeWillNOTRelease) {if (this->m_pRefInfo && this->m_pRefInfo->_bResponsible) {if (--(this->m_pRefInfo->_nRefCnt) == 0) {g_Data_MemMgt.ReturnMem(this->m_pRefInfo->_pData);g_RefS_MemMgt.ReturnMem(this->m_pRefInfo);}}m_pRefInfo = g_RefS_MemMgt.AllocateMem(1);m_pRefInfo->_bResponsible = false;m_pRefInfo->_pData = pMemWeWillNOTRelease;return (*this);}~MemPointer() {if (m_pRefInfo) {if (m_pRefInfo->_bResponsible) {if (--(m_pRefInfo->_nRefCnt) == 0) {g_Data_MemMgt.ReturnMem(m_pRefInfo->_pData);g_RefS_MemMgt.ReturnMem(m_pRefInfo);}}else {g_RefS_MemMgt.ReturnMem(m_pRefInfo);} }}T& operator[] (int index) { // now access elements in an array like you learned it from the firs time!if (m_pRefInfo == nullptr) {throw "No memory is pointed!";}else if (m_pRefInfo->_bResponsible && (index < 0 || index >= (int)m_pRefInfo->_size)) {throw "Array index out of bound!"; // PKATHLON: should I care?}return (m_pRefInfo->_pData)[index];}unsigned int Size() const {if (m_pRefInfo == nullptr) {throw "No memory is pointed!";}else if (!m_pRefInfo->_bResponsible) {return -1;}else {return m_pRefInfo->_size;}}protected:struct refStruct {bool _bResponsible;unsigned int _size; // number of elements <T>std::atomic_int _nRefCnt; // atomic types is the single best feature of c++11 according to PKATHLONT *_pData;};refStruct *m_pRefInfo;static FixedAllocatedMem<T> g_Data_MemMgt;static FixedAllocatedMem<refStruct> g_RefS_MemMgt;};template <typename T> FixedAllocatedMem<T> MemPointer<T>::g_Data_MemMgt;template <typename T> FixedAllocatedMem<typename MemPointer<T>::refStruct> MemPointer<T>::g_RefS_MemMgt;}#endif
main.cpp
#include <chrono>#include "MemManagement.h"int main(){std::chrono::system_clock::time_point t0 = std::chrono::high_resolution_clock::now();#if 0using namespace Customized_MemoryManagement;for (int i = 0; i < 1000000; ++i){MemPointer<double> p0(10000);MemPointer<double> p1 = p0;p1[0] = 3.0;p1[1] = 1.1;double asd[10000];p0 = asd;p0[0] = -3.0;p0[1] = -1.1; // don't need to care about memory deallocation}#elsefor (int i = 0; i < 1000000; ++i){double *p0 = new double[10000];double *p1 = p0;p1[0] = 3.0;p1[2] = 1.1;double asd[10000];p0 = asd;p0[0] = -3.0;p0[1] = -1.1;delete[] p1; // "delete[] p0;" will cause memory leak and crash here!}#endifstd::chrono::system_clock::time_point t1 = std::chrono::high_resolution_clock::now();double timediff = std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count() / (1e6);std::cout << "Elapsed time = " << timediff << " milliseconds...\n";getchar();return 0;}
阅读全文
0 0
- 一个简单的C++内存管理与引用计数指针
- OC的内存管理 与 引用计数
- 引用计数与内存管理
- cocos2dx-内存管理剖析(智能指针的局限与引用计数的选择)
- C++内存管理--简单的引用计数的实现
- objective-C 的内存管理之-引用计数
- objective-C 的内存管理之-引用计数
- OC 内存管理 --- 引用计数简单使用
- Objective-C内存管理之引用计数
- Object-C 内存管理引用计数
- 关于内存管理引用计数与变量生命周期的关系
- OC使用引用计数的内存管理
- OC的内存管理引用计数机制
- 使用引用计数扩展c语言实现内存自动管理的思考 -- 为什么存在内存泄露
- objective-c中的内存管理——引用计数、ARC与MRC(1)
- objective-c 的引用计数管理
- Objective-C内存管理之引用计数(一)
- Objective-C内存管理详解——引用计数
- 中国首位职业慈善家卢星宇来榆林演讲
- 线程池
- 对比线程安全和可重入函数
- 面试基础知识漫谈(参考)
- 【脚本语言系列】关于Python操作数据文本字符串,你需要知道的事
- 一个简单的C++内存管理与引用计数指针
- JDK、Maven环境变量配置
- 代理服务器与NAT技术
- ACM题目中几种常见形式的输入数据的处理(C++版)
- Socket PRGM: chat_1Vn
- Python--多线程网络编程
- [堆] hihoCoder Challenge 29 D. 不上升序列
- [leetcode] Add to List 169. Majority Element
- 震撼发布2017年Android百大框架排行榜