支持HW团队,就支付宝领取下面的红包吧!(2018年3月31前,就几毛,也会几块,可以和其他红包叠加使用),你领取消费,HW有奖励。红包使用无条件限制,有条件请注意是不是有病毒。

小伙伴们,给大家发红包喽!人人可领,领完就能用。祝大家领取的红包金额大大大!#吱口令#长按复制此消息,打开支付宝就能领取!er1OEj73Uj

登入 注册 | 验证
| 搜索
HelloWorld论坛 : > 计算机科学、技术、教学> 编程专题> 开源免费项目> [原创]ACE内存分配——不定长数据,不定量个数分配(一)——用几个定长数据,不定量个数分配实现
 
 
 
 
 
 
类别:ACE 阅读:3114 评论:0 时间:五月 20, 2013, 10 a.m. 关键字:ACE 内存

 

看了ACE_Dynamic_Cached_Allocator,以为是实现不定长数据分配的,原来ACE_Cached_Allocator实质是一个东西,但是现实当中,我们的内存一般使用是固定的,也足可以满足要求。

现在我们设计一款不定长,不定量的内存分配器。 ACE_Message_Block 构造中,使用了三个分配器,Allocator_stratey,data_block_allocator,message_block_allocator,这三个分配器是分别为ACE_Message_Block对象,ACE_Data_Block对象,以及data_block指向的内存。sizeof(ACE_Message_Block)=40,sizeof(ACE_Data_Block) = 40,也许你要使用ACE_Message_Block的基类,但是他们大小差不多,所以我们可以用较大内存的定长的分配器来解决。至于消息(char*),我们这里假设数据不会大于S_BUFSIZ=1024的3倍。其中1倍比较多,二倍,三倍很少。

我们将要实现这样一个类。

1.进行3级分配,你可以很容易改成其他级别。分别为一级:ACE_Message_Block,ACE_Data_Block,或者其基类,因为内存大小差距不大。二级:S_BUFSIZ的1倍,主要给数据使用,这个比较多使用,我们独立出来。三级:3倍的S_BUFSIZ,这种情况就不多了,但是,还是不能忽视。至于3倍以上的情况,我们下篇文章考虑。我们设定一次申请个数。

2、我们参考[原创]ACE内存分配——定长数据分配(一),里面的模板给我们实现提供了思路,一个管理类,下面很多分配器,实现动态分配。但是里面的模板改变了接口,这样实现不友好。

3、我们参考[原创]ACE内存分配——定长数据分配(二),里面的HwCachedMemPoolNodeg给我们实现提供了办法。

#if (defined HW_ACE) && (defined HW_ACE_ALLOCATOR)  //使用自定义内存管理
#ifndef _H_hwnet_block_allocator_
#define _H_hwnet_block_allocator_

#include "ace/Malloc.h"
#include <ace/Malloc_T.h>

namespace hwnet
{
        template <class T, class ACE_LOCK>
        class CachedAllocator;
        template <class T, class ACE_LOCK>
        class DateNode
        {
        public:
                DateNode<T, ACE_LOCK>(CachedAllocator<T, ACE_LOCK>* pParent)
                        : m_pParent(pParent)
                {
                        assert(m_pParent);
                }
                /// Return the address of free memory.
                void* addr (void)
                {
                        return &m_bDate;
                }
                /// Get the next DateNode in a list.
                DateNode<T, ACE_LOCK> *get_next (void)
                {
                        return next_;
                }

                /// Set the next DateNode.
                void set_next (DateNode<T, ACE_LOCK> *ptr)
                {
                        next_ = ptr;
                }

        private:
                CachedAllocator<T, ACE_LOCK>* m_pParent;
                union
                {
                        char m_bDate[sizeof(T)];
                        /**
                        * Since memory is not used when placed in a free list,
                        * we can use it to maintain the structure of free list.
                        * I was using union to hide the fact of overlapping memory
                        * usage.  However, that cause problem on MSVC.  So, I now turn
                        * back to hack this with casting.
                        */
                        DateNode<T, ACE_LOCK> *next_;
                };
        };
        template <class T, class ACE_LOCK>
        class CachedAllocator : public ACE_New_Allocator
        {
        public:
                /// Create a cached memory pool with @a n_chunks chunks
                /// each with sizeof (TYPE) size.
                CachedAllocator(ManageAllocator<T, ACE_LOCK>* pParent, size_t n_chunks)
                        : m_pParent(pParent)
                        , pool_ (0),
                        free_list_ (ACE_PURE_FREE_LIST)
                {
                        // To maintain alignment requirements, make sure that each element
                        // inserted into the free list is aligned properly for the platform.
                        // Since the memory is allocated as a char[], the compiler won't help.
                        // To make sure enough room is allocated, round up the size so that
                        // each element starts aligned.
                        //
                        // NOTE - this would probably be easier by defining pool_ as a pointer
                        // to T and allocating an array of them (the compiler would probably
                        // take care of the alignment for us), but then the ACE_NEW below would
                        // require a default constructor on T - a requirement that is not in
                        // previous versions of ACE
                        size_t chunk_size = sizeof (T);
                        chunk_size = ACE_MALLOC_ROUNDUP (chunk_size, ACE_MALLOC_ALIGN);
                        ACE_NEW (this->pool_,
                                char[n_chunks * chunk_size]);

                        for (size_t c = 0;
                                c < n_chunks;
                                c++)
                        {
                                void* placement = this->pool_ + c * chunk_size;
                                this->free_list_.add (new (placement) ACE_Cached_Mem_Pool_Node<T>);
                        }
                        // Put into free list using placement contructor, no real memory
                        // allocation in the above <new>.
                }

                /// Clear things up.
                ~ACE_Cached_Allocator (void)
                {
                        delete [] this->pool_;
                }

                /**
                * Get a chunk of memory from free list cache.  Note that @a nbytes is
                * only checked to make sure that it's less or equal to sizeof T, and is
                * otherwise ignored since @c malloc() always returns a pointer to an
                * item of sizeof (T).
                */
                void *malloc (size_t nbytes = sizeof (T))
                {
                        // Check if size requested fits within pre-determined size.
                        if (nbytes > sizeof (T))
                                return 0;

                        // addr() call is really not absolutely necessary because of the way
                        // ACE_Cached_Mem_Pool_Node's internal structure arranged.
                        return this->free_list_.remove ()->addr ();
                }

                /**
                * Get a chunk of memory from free list cache, giving them
                * @a initial_value.  Note that @a nbytes is only checked to make sure
                * that it's less or equal to sizeof T, and is otherwise ignored since
                * calloc() always returns a pointer to an item of sizeof (T).
                */
                virtual void *calloc (size_t nbytes,
                        char initial_value = '\0')
                {
                        // Check if size requested fits within pre-determined size.
                        if (nbytes > sizeof (T))
                                return 0;

                        // addr() call is really not absolutely necessary because of the way
                        // ACE_Cached_Mem_Pool_Node's internal structure arranged.
                        void *ptr = this->free_list_.remove ()->addr ();
                        if (ptr != 0)
                                ACE_OS::memset (ptr, initial_value, sizeof (T));
                        return ptr;
                }

                /// This method is a no-op and just returns 0 since the free list
                /// only works with fixed sized entities.
                virtual void *calloc (size_t n_elem,
                        size_t elem_size,
                        char initial_value = '\0')
                {
                        ACE_NOTSUP_RETURN (0);
                }

                /// Return a chunk of memory back to free list cache.
                void free (void *  ptr)
                {
                        if (ptr != 0)
                                this->free_list_.add ((ACE_Cached_Mem_Pool_Node<T> *) ptr) ;
                }

                /// Return the number of chunks available in the cache.
                size_t pool_depth (void)
                {
                        return this->free_list_.size ();
                }

        private:
                ManageAllocator<T, ACE_LOCK>* m_pParent;
                /// Remember how we allocate the memory in the first place so
                /// we can clear things up later.
                char *pool_;

                /// Maintain a cached memory free list.
                ACE_Locked_Free_List<DateNode<T>, ACE_LOCK> free_list_;
        };
}
#endif // #ifndef _H_hwnet_block_allocator_
#endif // HW_ACE HW_ACE_ALLOCATOR  //使用自定义内存管理

   经思考我写出了如上代码,后来一想,CachedAllocator 就是 ACE_Cached_Allocator,只不过节点类型变了,我何不直接使用ACE_Cached_Allocator,数据前面加一个ACE_Cached_Allocator父节点。还可以在改进,直接用ACE_Dynamic_Cached_Allocator。DateNode改为

#if (defined HW_ACE) && (defined HW_ACE_ALLOCATOR)  // 使用自定义内存管理
#ifndef _H_hwnet_date_allocator_
#define _H_hwnet_date_allocator_

#include "ace/Malloc.h"
#include <ace/Malloc_T.h>
#include <boost/shared_ptr.hpp>

namespace hwnet
{
        template <class ACE_LOCK>
        class DateNode
        {
        public:
                DateNode<ACE_LOCK>(ACE_Allocator* pParent)
                        : m_pParent(pParent)
                {
                        assert(m_pParent);
                }
                ~DateNode<ACE_LOCK>()
                {
                        assert(m_pParent);
                        m_pParent->free(this);
                }
                static DateNode<ACE_LOCK>* GetDateNode(void* ptr)
                {
                        if (ptr)
                        {
                                return (DateNode<ACE_LOCK>*)((char*)ptr + sizeof(DateNode<ACE_LOCK>));
                        }
                        return NULL;
                }

        private:
                ACE_Allocator* m_pParent;
        };
        template <class ACE_LOCK>
        class AllocatorNode
                : public ACE_New_Allocator
        {
                typedef ACE_Dynamic_Cached_Allocator<ACE_LOCK> ACEBlockAllocator;
        public:
                AllocatorNode(size_t MinBufSize // 最小数据内存
                        , size_t MaxBufSum // 一次申请个数
                        )
                        : m_MinBufSize(MinBufSize) //  最小数据内存
                        , m_MaxBufSum(MaxBufSum) // 一次申请个数
#ifdef _DEBUG
                        , m_uSim(0) // 已经使用数量
#else
#endif
                {
                }
                ~AllocatorNode()
                {
                        for (std::deque<ACEBlockAllocator*>::iterator ite = m_deqAllocator.begin()
                                ; ite != m_deqAllocator.end()
                                ; ite++)
                        {
                                delete *ite;
                        }
                }
                virtual void *malloc (size_t nbytes)
                {
                        if (nbytes > m_MinBufSize)
                        {
                                return NULL;
                        }
                        ACE_GUARD_RETURN (ACE_LOCK, monitor, this->m_lock, NULL);
#ifdef _DEBUG
                        // 还有空闲
                        for (int i=m_deqAllocator.size()/2; i>=0; i--)
#else
#endif
                        {
                                for (std::deque<ACEBlockAllocator*>::iterator ite = m_deqAllocator.begin()
                                        ; ite != m_deqAllocator.end()
                                        ; ite++)
                                {
                                        ACEBlockAllocator* pAllocator = *ite;
                                        if (pAllocator->pool_depth() > 0)
                                        {
                                                m_uSim++;
                                                void* ptr = pAllocator->malloc(nbytes);
                                                if (ptr)
                                                {
#ifdef _DEBUG
                                                        new (ptr) DateNode<ACE_LOCK>(dynamic_cast<ACE_Allocator*>(this));
#else
                                                        new (ptr) DateNode<ACE_LOCK>(dynamic_cast<ACE_Allocator*>(pAllocator));
#endif
                                                }
                                                return (char*)ptr + sizeof(DateNode<ACE_LOCK>);
                                        }
                                        else
                                        {
                                                m_deqAllocator.pop_front();
                                                m_deqAllocator.push_back(pAllocator);
                                        }
                                }
                        }
                        // 重新分配
                        ACEBlockAllocator* pAllocator = new ACEBlockAllocator(m_MaxBufSum, m_MinBufSize + sizeof(ACE_New_Allocator*));
                        m_deqAllocator.push_front(pAllocator);
                        void* ptr = pAllocator->malloc(nbytes);
                        if (ptr)
                        {
                                m_uSim++;
#ifdef _DEBUG
                                new (ptr) DateNode<ACE_LOCK>(dynamic_cast<ACE_Allocator*>(this));
#else
                                new (ptr) DateNode<ACE_LOCK>(dynamic_cast<ACE_Allocator*>(pAllocator));
#endif
                        }
                        return (char*)ptr + sizeof(DateNode<ACE_LOCK>);
                }
                virtual void *calloc (size_t nbytes, char initial_value = '\0')
                {
                        void* ptr = malloc(nbytes);
                        if (ptr)
                        {
                                ACE_OS::memset (ptr, initial_value, nbytes);
                        }

                        return ptr;
                }
                virtual void *calloc (size_t n_elem, size_t elem_size, char initial_value = '\0')
                {
                        return calloc (n_elem * elem_size, initial_value);
                }
                virtual void free (void* ptr)
                {
#ifdef _DEBUG
                        assert(m_uSim > 0);
#else
#endif
                        //ACE_GUARD (ACE_LOCK, monitor, this->m_lock);
                        if (ptr)
                        {
                                DateNode<ACE_LOCK>::GetDateNode(ptr)->~DateNode<ACE_LOCK>();
#ifdef _DEBUG
                                m_uSim--;
#else
#endif
                        }
                }
        private:
                ACE_LOCK m_lock;
                size_t m_MinBufSize; // 最小数据内存
                size_t m_MaxBufSum; // 一次申请个数
                std::deque<ACEBlockAllocator*> m_deqAllocator;
#ifdef _DEBUG
                ACE_Atomic_Op<ACE_LOCK, size_t> m_uSim; // 已经使用数量
#else
#endif
        };
}
#endif // #ifndef _H_hwnet_date_allocator_
#endif // HW_ACE HW_ACE_ALLOCATOR  //使用自定义内存管理

    完整代码如下:

/***************************************************************
version:  1.0
date: 16/5/2013   17:04
FileName:     hwnet_block_allocator.h
Author:       丁灵峰
Compiled on:   VC.net 2008
-------------------------------------------------------------
Description:
Modification history:
Other:

-------------------------------------------------------------
Copyright (C) 2010 - All Rights Reserved
***************************************************************

****************************************************************/
#if (defined HW_ACE) && (defined HW_ACE_ALLOCATOR)  // 使用自定义内存管理
#ifndef _H_hwnet_date_allocator_
#define _H_hwnet_date_allocator_

#include "ace/Malloc.h"
#include <ace/Malloc_T.h>
#include <boost/shared_ptr.hpp>

namespace hwnet
{
        template <class ACE_LOCK>
        class ManageAllocator;
        template <class ACE_LOCK>
        class AllocatorNode;
        template <class ACE_LOCK>
        class DateNode
        {
        public:
                DateNode<ACE_LOCK>(ACE_Allocator* pParent)
                        : m_pParent(pParent)
                {
                        assert(m_pParent);
                }
                ~DateNode<ACE_LOCK>()
                {
                        assert(m_pParent);
                        m_pParent->free(this);
                }
                static DateNode<ACE_LOCK>* GetDateNode(void* ptr)
                {
                        if (ptr)
                        {
                                return (DateNode<ACE_LOCK>*)((char*)ptr + sizeof(DateNode<ACE_LOCK>));
                        }
                        return NULL;
                }

        private:
                ACE_Allocator* m_pParent;
        };
        template <class ACE_LOCK>
        class AllocatorNode
                : public ACE_New_Allocator
        {
                typedef ACE_Dynamic_Cached_Allocator<ACE_LOCK> ACEBlockAllocator;
        public:
                AllocatorNode(size_t MinBufSize // 最小数据内存
                        , size_t MaxBufSum // 一次申请个数
                        )
                        : m_MinBufSize(MinBufSize) //  最小数据内存
                        , m_MaxBufSum(MaxBufSum) // 一次申请个数
#ifdef _DEBUG
                        , m_uSim(0) // 已经使用数量
#else
#endif
                {
                }
                ~AllocatorNode()
                {
                        for (std::deque<ACEBlockAllocator*>::iterator ite = m_deqAllocator.begin()
                                ; ite != m_deqAllocator.end()
                                ; ite++)
                        {
                                delete *ite;
                        }
                }
                virtual void *malloc (size_t nbytes)
                {
                        if (nbytes > m_MinBufSize)
                        {
                                return NULL;
                        }
                        ACE_GUARD_RETURN (ACE_LOCK, monitor, this->m_lock, NULL);
#ifdef _DEBUG
                        // 还有空闲
                        for (int i=m_deqAllocator.size()/2; i>=0; i--)
#else
#endif
                        {
                                for (std::deque<ACEBlockAllocator*>::iterator ite = m_deqAllocator.begin()
                                        ; ite != m_deqAllocator.end()
                                        ; ite++)
                                {
                                        ACEBlockAllocator* pAllocator = *ite;
                                        if (pAllocator->pool_depth() > 0)
                                        {
                                                m_uSim++;
                                                void* ptr = pAllocator->malloc(nbytes);
                                                if (ptr)
                                                {
#ifdef _DEBUG
                                                        new (ptr) DateNode<ACE_LOCK>(dynamic_cast<ACE_Allocator*>(this));
#else
                                                        new (ptr) DateNode<ACE_LOCK>(dynamic_cast<ACE_Allocator*>(pAllocator));
#endif
                                                }
                                                return (char*)ptr + sizeof(DateNode<ACE_LOCK>);
                                        }
                                        else
                                        {
                                                m_deqAllocator.pop_front();
                                                m_deqAllocator.push_back(pAllocator);
                                        }
                                }
                        }
                        // 重新分配
                        ACEBlockAllocator* pAllocator = new ACEBlockAllocator(m_MaxBufSum, m_MinBufSize + sizeof(ACE_New_Allocator*));
                        m_deqAllocator.push_front(pAllocator);
                        void* ptr = pAllocator->malloc(nbytes);
                        if (ptr)
                        {
                                m_uSim++;
#ifdef _DEBUG
                                new (ptr) DateNode<ACE_LOCK>(dynamic_cast<ACE_Allocator*>(this));
#else
                                new (ptr) DateNode<ACE_LOCK>(dynamic_cast<ACE_Allocator*>(pAllocator));
#endif
                        }
                        return (char*)ptr + sizeof(DateNode<ACE_LOCK>);
                }
                virtual void *calloc (size_t nbytes, char initial_value = '\0')
                {
                        void* ptr = malloc(nbytes);
                        if (ptr)
                        {
                                ACE_OS::memset (ptr, initial_value, nbytes);
                        }

                        return ptr;
                }
                virtual void *calloc (size_t n_elem, size_t elem_size, char initial_value = '\0')
                {
                        return calloc (n_elem * elem_size, initial_value);
                }
                virtual void free (void* ptr)
                {
#ifdef _DEBUG
                        assert(m_uSim > 0);
#else
#endif
                        //ACE_GUARD (ACE_LOCK, monitor, this->m_lock);
                        if (ptr)
                        {
                                DateNode<ACE_LOCK>::GetDateNode(ptr)->~DateNode<ACE_LOCK>();
#ifdef _DEBUG
                                m_uSim--;
#else
#endif
                        }
                }
        private:
                ACE_LOCK m_lock;
                size_t m_MinBufSize; // 最小数据内存
                size_t m_MaxBufSum; // 一次申请个数
                std::deque<ACEBlockAllocator*> m_deqAllocator;
#ifdef _DEBUG
                ACE_Atomic_Op<ACE_LOCK, size_t> m_uSim; // 已经使用数量
#else
#endif
        };
        template <class ACE_LOCK>
        class ManageAllocator
                : public ACE_New_Allocator
                //: public 
        {
                // 友元
        public:
                // 静态属性
                // 静态函数
                // 静态工具
                // 接口实现

                // 构造于析构
        public:
                virtual ~ManageAllocator(void)
                {
                }
                ManageAllocator(std::set<size_t>& setMinSize // 最小数据内存,定长处理
                        , size_t MinBufSize // 最小数据内存,不定长用
                        , size_t MaxBufSum // 一次申请个数
                        )
                        // 不定长数据处理
#ifdef _DEBUG
                        : m_uSim(0) // 已经使用数量
#else
#endif
                {
                        for (std::set<size_t>::iterator ite=setMinSize.begin()
                                ; ite != setMinSize.end()
                                ; ite++)
                        {
                                m_mapAllocatorNode[*ite] = boost::shared_ptr<AllocatorNode<ACE_LOCK> >(new AllocatorNode<ACE_LOCK>(*ite, MaxBufSum));
                        }
                }

                // 操作函数
        public:
                virtual void *malloc (size_t nbytes)
                {
                        ACE_GUARD_RETURN (ACE_LOCK, monitor, this->m_lock, NULL);
                        // 分级
                        std::map<long, boost::shared_ptr<AllocatorNode<ACE_LOCK> > > m_mapAllocatorNode;
                        for (std::map<long, boost::shared_ptr<AllocatorNode<ACE_LOCK> > >::iterator ite = m_mapAllocatorNode.begin()
                                ; ite != m_mapAllocatorNode.end()
                                ; ite++)
                        {
                                if (nbytes <= ite->first)
                                {
                                        void* ptr = ite->second->malloc(nbytes);
                                        if (ptr)
                                        {
#ifdef _DEBUG
                                                m_uSim++;
#else
#endif
                                                return ptr;
                                        }
                                }
                        }
                        // 不定长数据处理
                        return NULL;
                }
                virtual void *calloc (size_t nbytes, char initial_value = '\0')
                {
                        void* ptr = malloc(nbytes);
                        if (ptr)
                        {
                                ACE_OS::memset (ptr, initial_value, nbytes);
                        }

                        return ptr;
                }
                virtual void *calloc (size_t n_elem, size_t elem_size, char initial_value = '\0')
                {
                        return calloc (n_elem * elem_size, initial_value);
                }
                virtual void free (void* ptr)
                {
                        assert(m_uSim.value() > 0);
                        ACE_GUARD (ACE_LOCK, monitor, this->m_lock);
                        if (ptr)
                        {
                                DateNode<ACE_LOCK>::GetDateNode(ptr)->~DateNode<ACE_LOCK>();
#ifdef _DEBUG
                                m_uSim--;
#else
#endif
                        }
                }

                /// Return the number of chunks available in the cache.
                size_t Size (void)
                {
                        return m_uSim.value();
                }

                // 工具函数
        private:
        protected:

                // 禁止
        private:
                ManageAllocator(const ManageAllocator&); //复制构造
                ManageAllocator & operator= (const ManageAllocator&); // 等于重载

                // 属性
        public:
        protected:
                ACE_LOCK m_lock;
                std::map<size_t, boost::shared_ptr<AllocatorNode<ACE_LOCK> > > m_mapAllocatorNode;
#ifdef _DEBUG
                ACE_Atomic_Op<ACE_LOCK, size_t> m_uSim; // 已经使用数量
#else
#endif
        };
}
#endif // #ifndef _H_hwnet_date_allocator_
#endif // HW_ACE HW_ACE_ALLOCATOR  //使用自定义内存管理

 我们这样使用,注意,这个有效是哟前提假设的,条件更宽的情况请看下一篇.

const static long S_BUFSIZ = 1024; // 一般申请大小,或者倍数
std::set<size_t> setMinSize;
boost::shared_ptr<ManageAllocator<ACE_SYNCH_RECURSIVE_MUTEX> >gPManageBlockAllocator;
setMinSize.insert(MAX(sizeof(ACE_Message_Block),sizeof(ACE_Data_Block)));
setMinSize.insert(S_BUFSIZ);
setMinSize.insert(S_BUFSIZ*3);
gPManageBlockAllocator.reset(new ManageAllocator<ACE_SYNCH_RECURSIVE_MUTEX>(setMinSize, S_BUFSIZ, S_BUFSIZ*4));
ACE_Allocator::instance (dynamic_cast<ACE_Allocator*>(gPManageBlockAllocator.get()));

 

[挂载人]初学MPEG

个人签名--------------------------------------------------------------------------------

Please Login (or Sign Up) to leave a comment