日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

apr_pool -- 内存池

發(fā)布時間:2024/4/11 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 apr_pool -- 内存池 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
這個指南主要介紹如何使用 libapr apache portable runtime )。
版權(quán)所有, Copyright (C) 2005 INOUE Seiichiro <inoue&ariel-networks.com> ,翻譯:成彥
原文地址: http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial.html
轉(zhuǎn)載時請保留版權(quán)信息。

大多數(shù) libapr API 都依賴于內(nèi)存池,借助內(nèi)存池,簡化了內(nèi)存塊的管理。想像一下沒有內(nèi)存池系統(tǒng)的情況:你申請一些內(nèi)存塊就必需逐個釋放它們,例如如果你申請了 10 個內(nèi)存塊,你必需釋放 10 次,否則,你將遭受內(nèi)存泄露的錯誤。內(nèi)存池解決了這個令人感到繁瑣的問題,在申請一個內(nèi)存池之后,你可以從內(nèi)存池中申請多個內(nèi)存塊,釋放它們的時候,你所需要做的就是銷毀內(nèi)存池,這樣你就可以釋放所有的內(nèi)存塊了。這有兩個優(yōu)點,第一,它可以預(yù)防內(nèi)存泄露的錯誤;第二,分配內(nèi)存塊的開銷相對變低了。從某種意義上說,內(nèi)存池迫使你遵循面向會話編程,一個內(nèi)存池就是一種會話內(nèi)容,這樣,處于同一個內(nèi)存池中的對象就有相同的生命周期,你可以通過控制會話內(nèi)容來控制對象。在一個會話的開始,你創(chuàng)建了一個內(nèi)存池,接著,你在內(nèi)存池中創(chuàng)建了一些對象,你不需要去關(guān)心這些對象的生命周期,最后,在會話結(jié)束的時候,你只需要將那個內(nèi)存池銷毀就可以了。

注:通常,對象生命周期控制是程序開發(fā)最困難的部分,因此,針對這個問題還存在有一些技術(shù),例如智能指針,垃圾回收機制等等。需要注意,同時使用這些技術(shù)有一定的難度,內(nèi)存池也是這其中的一項技術(shù),所以你不得不非常小心的使用它們。

注:在將來, libapr 的內(nèi)存池將變得不再那么重要。參見 http://mail-archives.apache.org/mod_mbox/apr-dev/200502.mbox/%3c1f1d9820502241330123f955f@mail.gmail.com%3e.

下面有三個基本的 API 函數(shù) :
/*?
摘自 ?apr_pools.h */
??? APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool, apr_pool_t *parent);
??? APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size);
??? APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p);

我們使用 apr_pool_create() 函數(shù)創(chuàng)建一個內(nèi)存池,這個內(nèi)存池將一直存活,直到你調(diào)用 apr_pool_destroy() 函數(shù)以后被銷毀。 apr_pool_create() 的第一個參數(shù)是一個結(jié)果輸出參數(shù),是一個新創(chuàng)建的 apr_pool_t 類型的內(nèi)存池對象。通過調(diào)用 apr_palloc() 來申請指定大小的內(nèi)存塊,具體使用方法見 mp-sample.c

/*?
摘自 ?mp-sample.c */
??? apr_pool_t *mp;
??? /*?
創(chuàng)建內(nèi)存池 ?*/
??? apr_pool_create(&mp, NULL);

??? /*?
從內(nèi)存池中分配內(nèi)存塊 ?*/
??? char *buf1;
??? buf1 = apr_palloc(mp, MEM_ALLOC_SIZE);

簡單地說,我們可以像使用 malloc(3) 這樣使用 apr_palloc() ,也可以調(diào)用 apr_pcalloc() ,正如你猜到的, apr_pcalloc 類似于 calloc(3) apr_pcalloc 返回一個被 0 填充了的內(nèi)存塊。假如你使用了 malloc(3)/calloc(3) ,你需要調(diào)用 free(3) 來釋放分配了的內(nèi)存。但是在內(nèi)存池中,你必不需要釋放每個內(nèi)存塊,你只需要對該內(nèi)存池調(diào)用 apr_poll_destroy() 函數(shù)從而釋放所有的內(nèi)存塊。

注:使用 apr_palloc() 申請內(nèi)存,其內(nèi)存塊的大小沒有限制,然而,在內(nèi)存池中申請大內(nèi)存并不是什么好主意。內(nèi)存池本質(zhì)上是為了更小的內(nèi)存塊而設(shè)計的,實際上,初始的內(nèi)存池的大小是 8000 字節(jié)。如果你需要申請超過幾兆字節(jié)的內(nèi)存塊時,那么就不要使用內(nèi)存池。
注:默認情況下,內(nèi)存池管理器從不將申請到的內(nèi)存歸還給系統(tǒng)。如果程序要運行很長時間,這將是一個問題,推薦像下面的代碼那樣指定一個上限:

/*?
設(shè)置上限,讓內(nèi)存池管理器釋放內(nèi)存,將內(nèi)存返回給系統(tǒng)的示例代碼 ?*/

#define YOUR_POOL_MAX_FREE_SIZE 32????? /* apr_pool max free list size */
apr_pool_t *mp;
apr_pool_create(&mp, NULL);
apr_allocator_t* pa = apr_pool_allocator_get(mp);
if (pa) {
??? apr_allocator_max_free_set(pa, YOUR_POOL_MAX_FREE_SIZE);
}

這兒有兩個 API 函數(shù)需要知道,一個是 apr_pool_clear() ,另一個是 apr_pool_cleanup_register() apr_pool_clear() 類似于 apr_pool_destroy() ,不同的是內(nèi)存池將一直存在。示例代碼如下:
/*?
使用 apr_pool_clear() 的例子 ?*/
apr_pool_t *mp;
apr_pool_create(&mp, NULL);
for (i = 0; i < n; ++i) {
??? do_operation(..., mp);
??? apr_pool_clear(mp);
}
apr_pool_destroy(mp);

do_operation()
里使用了內(nèi)存池,分配了一些內(nèi)存塊。假如在 do_operation() 之外不需要這些內(nèi)存塊了,可以調(diào)用 apr_pool_clear() 函數(shù),這樣能縮小內(nèi)存的使用大小。如果你熟悉系統(tǒng)的棧內(nèi)存的話,你會覺得內(nèi)存池與棧內(nèi)存一樣,調(diào)用 apr_palloc 只是如同移動 SP (棧指針),調(diào)用 apr_pool_clear() 如同重置 SP ,兩者都是輕量級的操作。

使用 apr_pool_cleanup_register() 函數(shù),可以在內(nèi)存池清空 / 銷毀上設(shè)定一個鉤子(回調(diào))函數(shù),在內(nèi)存池清空或是銷毀后調(diào)用這個函數(shù),在這個回調(diào)函數(shù)中,你可以實現(xiàn)任何在內(nèi)存池上的結(jié)束代碼。

關(guān)于內(nèi)存池的最后一個主題是子池,每個內(nèi)存池都可以有一個父內(nèi)存池,因此,內(nèi)存池構(gòu)造了樹。 apr_pool_create() 的第二個參數(shù)表示父內(nèi)存池,當(dāng)這個參數(shù)為 NULL 時,新創(chuàng)建的內(nèi)存池將變?yōu)橐粋€根內(nèi)存池,可以在這個根內(nèi)存池上創(chuàng)建子內(nèi)存池。在這個樹中對一個內(nèi)存池調(diào)用 apr_pool_destroy() 函數(shù),則該內(nèi)存池的子內(nèi)存池也將被銷毀;當(dāng)對該內(nèi)存池調(diào)用 apr_pool_clear() 函數(shù),則這個內(nèi)存池存在但是它的子內(nèi)存池將被銷毀,上面提及到的那些清除函數(shù),在子內(nèi)存池銷毀時被調(diào)用。

注:當(dāng)將 NULL 值做為清除回調(diào)函數(shù)時將會產(chǎn)生一個 bug ,你必須像下面的代碼那樣傳入 apr_pool_cleanup_null
/*?
關(guān)于內(nèi)存池典型 bug 的偽代碼 ?*/
/* apr_pool_cleanup_register(mp, ANY_CONTEXT_OF_YOUR_CODE, ANY_CALLBACK_OF_YOUR_CODE, NULL);?
這將產(chǎn)生一個 bug */
/*?
修正: ?*/

apr_pool_cleanup_register(mp, ANY_CONTEXT_OF_YOUR_CODE, ANY_CALLBACK_OF_YOUR_CODE, apr_pool_cleanup_null);

一個簡單的示例:

注意編譯時候加上:

LIBS := -lactivemq-cpp -lvoltdbcpp -lpq

//============================================================================ // Name : tt.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================#include <stdio.h> #include <string.h> #include <iostream> #include <vector> #include <boost/unordered_map.hpp> #include <boost/threadpool.hpp> #include<apr_pools.h>using namespace std;class APRMemoryPool { public:APRMemoryPool();virtual ~APRMemoryPool();public:static APRMemoryPool* get_instance();long init();long uninit();void* malloc(boost::thread::id threadid,size_t alloc_size);void free(boost::thread::id threadid);protected:long alloc_new_pool(boost::thread::id threadid, apr_pool_t** new_alloc_pool);long release_unused_pool(apr_pool_t** release_pool);private:apr_pool_t* root_pool;vector<apr_pool_t*> recycled_apr_pools;boost::unordered_map< boost::thread::id, apr_pool_t* > using_pools;boost::mutex pools_mutex_map;boost::mutex pools_mutex_vector; }; APRMemoryPool gl_APRMemoryMgr;APRMemoryPool* APRMemoryPool::get_instance(){return &gl_APRMemoryMgr; }APRMemoryPool::APRMemoryPool() :root_pool(NULL){ }APRMemoryPool::~APRMemoryPool(){uninit(); }long APRMemoryPool::init(){apr_pool_initialize();apr_pool_create(&root_pool,NULL);return 0; }long APRMemoryPool::uninit(){apr_pool_destroy(root_pool);apr_pool_terminate();return 0; }void* APRMemoryPool::malloc(boost::thread::id threadid, size_t alloc_size){apr_pool_t *thread_memory_pool = NULL;{boost::unique_lock<boost::mutex> malloc_lock(pools_mutex_map);boost::unordered_map<boost::thread::id, apr_pool_t*>::iterator iter = using_pools.find(threadid);if(iter != using_pools.end()){thread_memory_pool = iter->second;return apr_palloc(thread_memory_pool,alloc_size);}else{if(recycled_apr_pools.size()!=0){thread_memory_pool = recycled_apr_pools.back();recycled_apr_pools.pop_back();using_pools.insert(make_pair(threadid,thread_memory_pool));return apr_palloc(thread_memory_pool,alloc_size);}else{apr_pool_create(&thread_memory_pool,root_pool);using_pools.insert(make_pair(threadid,thread_memory_pool));cout<<"apr pool create a new one..............."<<endl;return apr_palloc(thread_memory_pool,alloc_size);}}} }void APRMemoryPool::free(boost::thread::id threadid) {apr_pool_t *release_pool = NULL;{boost::unique_lock<boost::mutex> free_lock(pools_mutex_map);boost::unordered_map<boost::thread::id,apr_pool_t*>::iterator iter = using_pools.find(threadid);if(iter != using_pools.end()){release_pool = iter->second;apr_pool_clear(release_pool);using_pools.erase(threadid);recycled_apr_pools.push_back(release_pool);}else{cout<<"unexcepted error....."<<endl;}} }long APRMemoryPool::alloc_new_pool(boost::thread::id threadid, apr_pool_t** alloc_new_pool) {return 0; }int main(int argc, char *argv[]) {APRMemoryPool::get_instance()->init();void *p=APRMemoryPool::get_instance()->malloc(boost::this_thread::get_id(),100);std::cout <<p <<std::endl;APRMemoryPool::get_instance()->init();return (0); }

總結(jié)

以上是生活随笔為你收集整理的apr_pool -- 内存池的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。