zoukankan      html  css  js  c++  java
  • C++ 封装私有堆(Private Heap)

      Private Heap 是 Windows 提供的一种内存内存机制,对于那些需要频繁分配和释放动态内存的应用程序来说,Private Heap 是提高应用程序性能的一大法宝,使用它能降低 new / malloc 的调用排队竞争以及内存空洞。Private Heap 的原理及应用的资料很多,这里就不一一介绍了,常用的 Private Heap API 有以下几个,具体介绍请参考帮助文档:

    HeapCreate();
    HeapDestroy();
    HeapAlloc();
    HeapReAlloc();
    HeapSize();
    HeapFree();
    HeapCompact();

      

      由于是 C 风格的 API,使用起来比较繁琐,因此本座在闲暇之余用 C++ 对这些 API 进行了封装,主要包括两个类:

    • CPrivateHeap:自动创建和销毁进程私有堆,每一个该类的对象都代表一个私有堆,所以该类对象的特点是: 一般生命周期都比较长,通常作为全局对象, 其他类的静态成员对象或者一些长生命周期类对象的成员。
    • CPrivateHeapBuffer<T>:在私有堆中自动分配和释放指定大小的内存,一般用于在函数体内分配和释放局部作用域的堆内存,从而避免对 CPrivateHeap::Alloc() 和 CPrivateHeap::Free() 的调用。
    #pragma once

    class CPrivateHeap
    {
    public:
    enum EnCreateOptions
    {
    CO_DEFAULT = 0,
    CO_NO_SERIALIZE = HEAP_NO_SERIALIZE,
    CO_GENERATE_EXCEPTIONS = HEAP_GENERATE_EXCEPTIONS,
    CO_NOSERIALIZE_GENERATEEXCEPTIONS
    = HEAP_NO_SERIALIZE |
    HEAP_GENERATE_EXCEPTIONS
    };

    enum EnAllocOptions
    {
    AO_DEFAULT = 0,
    AO_ZERO_MEMORY = HEAP_ZERO_MEMORY,
    AO_NO_SERIALIZE = HEAP_NO_SERIALIZE,
    AO_GENERATE_EXCEPTIONS = HEAP_GENERATE_EXCEPTIONS,
    AO_ZEROMEMORY_NOSERIALIZE
    = HEAP_ZERO_MEMORY |
    HEAP_NO_SERIALIZE,
    AO_ZEROMEMORY_GENERATEEXCEPTIONS
    = HEAP_ZERO_MEMORY |
    HEAP_GENERATE_EXCEPTIONS,
    AO_NOSERIALIZE_GENERATESEXCEPTIONS
    = HEAP_NO_SERIALIZE |
    HEAP_GENERATE_EXCEPTIONS,
    AO_ZEROMEMORY_NOSERIALIZE_GENERATESEXCEPTIONS
    = HEAP_ZERO_MEMORY |
    HEAP_NO_SERIALIZE |
    HEAP_GENERATE_EXCEPTIONS
    };

    enum EnReAllocOptions
    {
    RAO_DEFAULT = 0,
    RAO_ZERO_MEMORY = HEAP_ZERO_MEMORY,
    RAO_NO_SERIALIZE = HEAP_NO_SERIALIZE,
    RAO_GENERATE_EXCEPTIONS = HEAP_GENERATE_EXCEPTIONS,
    RAO_REALLOC_IN_PLACE_ONLY = HEAP_REALLOC_IN_PLACE_ONLY,
    RAO_ZEROMEMORY_NOSERIALIZE
    = HEAP_ZERO_MEMORY |
    HEAP_NO_SERIALIZE,
    RAO_ZEROMEMORY_GENERATEEXCEPTIONS
    = HEAP_ZERO_MEMORY |
    HEAP_GENERATE_EXCEPTIONS,
    RAO_ZEROMEMORY_REALLOCINPLACEONLY
    = HEAP_ZERO_MEMORY |
    HEAP_REALLOC_IN_PLACE_ONLY,
    RAO_NOSERIALIZE_GENERATESEXCEPTIONS
    = HEAP_NO_SERIALIZE |
    HEAP_GENERATE_EXCEPTIONS,
    RAO_NOSERIALIZE_REALLOCINPLACEONLY
    = HEAP_NO_SERIALIZE |
    HEAP_REALLOC_IN_PLACE_ONLY,
    RAO_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
    = HEAP_GENERATE_EXCEPTIONS |
    HEAP_REALLOC_IN_PLACE_ONLY,
    RAO_ZEROMEMORY_NOSERIALIZE_GENERATESEXCEPTIONS
    = HEAP_ZERO_MEMORY |
    HEAP_NO_SERIALIZE |
    HEAP_GENERATE_EXCEPTIONS,
    RAO_ZEROMEMORY_NOSERIALIZE_REALLOCINPLACEONLY
    = HEAP_ZERO_MEMORY |
    HEAP_NO_SERIALIZE |
    HEAP_REALLOC_IN_PLACE_ONLY,
    RAO_ZEROMEMORY_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
    = HEAP_ZERO_MEMORY |
    HEAP_GENERATE_EXCEPTIONS |
    HEAP_REALLOC_IN_PLACE_ONLY,
    RAO_NOSERIALIZE_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
    = HEAP_NO_SERIALIZE |
    HEAP_GENERATE_EXCEPTIONS |
    HEAP_REALLOC_IN_PLACE_ONLY,
    RAO_ZEROMEMORY_NOSERIALIZE_GENERATESEXCEPTIONS_REALLOCINPLACEONLY
    = HEAP_ZERO_MEMORY |
    HEAP_NO_SERIALIZE |
    HEAP_GENERATE_EXCEPTIONS |
    HEAP_REALLOC_IN_PLACE_ONLY
    };

    enum EnSizeOptions
    {
    SO_DEFAULT = 0,
    SO_NO_SERIALIZE = HEAP_NO_SERIALIZE
    };

    enum EnFreeOptions
    {
    FO_DEFAULT = 0,
    FO_NO_SERIALIZE = HEAP_NO_SERIALIZE
    };

    enum EnCompactOptions
    {
    CPO_DEFAULT = 0,
    CPO_NO_SERIALIZE = HEAP_NO_SERIALIZE
    };

    public:
    PVOID Alloc(DWORD size, EnAllocOptions options = AO_DEFAULT)
    {return ::HeapAlloc(m_heap, options, size);}

    PVOID ReAlloc(PVOID pvmem, DWORD size, EnReAllocOptions options = RAO_DEFAULT)
    {return ::HeapReAlloc(m_heap, options, pvmem, size);}

    DWORD Size(PVOID pvmem, EnSizeOptions options = SO_DEFAULT)
    {return (DWORD)::HeapSize(m_heap, options, pvmem);}

    BOOL Free(PVOID pvmem, EnFreeOptions options = FO_DEFAULT)
    {return ::HeapFree(m_heap, options, pvmem);}

    DWORD Comapct(EnCompactOptions options = CPO_DEFAULT)
    {return (DWORD)::HeapCompact(m_heap, options);}

    BOOL IsValid() {return m_heap != NULL;}

    public:
    CPrivateHeap(EnCreateOptions options = CO_DEFAULT, DWORD initsize = 0, DWORD maxsize = 0)
    {m_heap = ::HeapCreate(options, initsize, maxsize);}

    ~CPrivateHeap() {if(IsValid()) ::HeapDestroy(m_heap);}

    private:
    CPrivateHeap(const CPrivateHeap&);
    CPrivateHeap operator = (const CPrivateHeap&);

    private:
    HANDLE m_heap;
    };

    template<class T>
    class CPrivateHeapBuffer
    {
    public:
    CPrivateHeapBuffer( CPrivateHeap& heap,
    DWORD size = 0,
    CPrivateHeap::EnAllocOptions allocoptions = CPrivateHeap::AO_DEFAULT,
    CPrivateHeap::EnFreeOptions freeoptions = CPrivateHeap::FO_DEFAULT)
    : m_hpPrivate(heap)
    , m_opFree(freeoptions)
    {
    ASSERT(m_hpPrivate.IsValid());
    m_pvMemory = (T*)m_hpPrivate.Alloc(size * sizeof(T), allocoptions);
    }

    ~CPrivateHeapBuffer() {m_hpPrivate.Free(m_pvMemory, m_opFree);}

    T* ReAlloc(DWORD size, CPrivateHeap::EnReAllocOptions options = CPrivateHeap::RAO_DEFAULT)
    {return m_pvMemory = (T*)m_hpPrivate.ReAlloc(m_pvMemory, size * sizeof(T), options);}

    DWORD Size(CPrivateHeap::EnSizeOptions options = CPrivateHeap::SO_DEFAULT)
    {return m_hpPrivate.Size(m_pvMemory, options);}

    operator T* () const {return m_pvMemory;}

    private:
    CPrivateHeapBuffer(const CPrivateHeapBuffer&);
    CPrivateHeapBuffer operator = (const CPrivateHeapBuffer&);

    private:
    CPrivateHeap& m_hpPrivate;
    T* m_pvMemory;
    CPrivateHeap::EnFreeOptions m_opFree;
    };

    typedef CPrivateHeapBuffer<BYTE> CPrivateHeapByteBuffer;
    typedef CPrivateHeapBuffer<TCHAR> CPrivateHeapStrBuffer;

      上述代码看起来挺复杂,但使用起来却是异常简单的,请看下面的使用示例:

    // 全局可见的 Heap
    CPrivateHeap g_heap;

    class MyClass
    {
    private:
    // 与类实例生命周期一致的 Heap
    CPrivateHeap m_heap;

    // 仅类内部可见的 Heap
    static CPrivateHeap sm_heap;

    public:
    void test_m_eap()
    {
    // 无需显式释放堆内存
    CPrivateHeapStrBuffer buff(m_heap, 32);
    lstrcpy(buff, _T("失败乃成功之母"));
    DWORD size = buff.Size();
    buff.ReAlloc(40 * sizeof(TCHAR));
    size = buff.Size();
    std::cout << (TCHAR*)buff << '\n';
    }

    static void test_sm_eap()
    {
    CPrivateHeapStrBuffer buff(sm_heap, 32);
    lstrcpy(buff, _T("失败乃成功之母"));
    DWORD size = buff.Size();
    buff.ReAlloc(40 * sizeof(TCHAR));
    size = buff.Size();
    std::cout << (TCHAR*)buff << '\n';
    }
    };

    void test_g_heap()
    {
    // 如果不使用 CPrivateHeapBuffer<T> 来封装堆内存

    ASSERT(g_heap.IsValid());
    TCHAR* pch = (TCHAR*)g_heap.Alloc(32 * sizeof(TCHAR));
    lstrcpy(pch, _T("失败乃成功之母"));
    DWORD size = g_heap.Size(pch);
    g_heap.ReAlloc(pch, 40 * sizeof(TCHAR));
    size = g_heap.Size(pch);
    std::cout << pch << '\n';

    // 需要显式释放堆内存
    g_heap.Free(pch);
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
    test_g_heap();

    MyClass::test_sm_eap();

    MyClass c;
    c.test_m_eap();

    return 0;
    }



     

    CodeProject

  • 相关阅读:
    DDD:四色原型中Role的 “六” 种实现方式
    .NET:脏读、不可重复读和幻读测试
    AIR:使用 HTML + Javascript 开发桌面应用
    Silverlight:《Pro Silverlight5》读书笔记 之 Layout
    设计原则:什么样的情况下需要引入父类?
    设计原则:不要为了复用而使用继承
    Ruby:字符集和编码学习总结
    .NET:字符集和编码学习总结
    Ruby:Sublime中开发Ruby需要注意的Encoding事项
    .NET:遇到并发问题,什么样的情况下需要自动重试?
  • 原文地址:https://www.cnblogs.com/ldcsaa/p/2348302.html
Copyright © 2011-2022 走看看