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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

不定长内存池之apr_pool

發布時間:2025/3/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 不定长内存池之apr_pool 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

內存池可有效降低動態申請內存的次數,減少與內核態的交互,提升系統性能,減少內存碎片,增加內存空間使用率,避免內存泄漏的可能性,這么多的優點,沒有理由不在系統中使用該技術。

內存池分類:

1、??????????????不定長內存池。典型的實現有apr_pool、obstack。優點是不需要為不同的數據類型創建不同的內存池,缺點是造成分配出的內存不能回收到池中。這是由于這種方案以session為粒度,以業務處理的層次性為設計基礎。

2、?????????????定長內存池。典型的實現有LOKI、BOOST。特點是為不同類型的數據結構分別創建內存池,需要內存的時候從相應的內存池中申請內存,優點是可以在使用完畢立即把內存歸還池中,可以更為細粒度的控制內存塊。
????與變長的相比,這種類型的內存池更加通用,另一方面對于大量不同的數據類型環境中,會浪費不少內存。但一般系統主要的數據結構都不會很多,并且都是重復申請釋放使用,這種情況下,定長內存池的這點小缺點可以忽略了。

一、apr

apr??apache?使用的底層庫,apache?是跨平臺的,其跨平臺正是基于?apr。個人覺得,使用apr有兩個好處,一是不用擔心跨平臺(事實上,我從來就不擔心,因為我寫的程序,從來都不跨平臺)。二是?apr??pool?很好用。pool?有兩個好處,一是可以理解成內存池,在?pool?分配的內存,是不用釋放的,pool?銷毀的時候自然會釋放這些內存(所以銷毀(清理)pool變得異常重要,千萬不能忘了)。二是可以理解成資源管理器,分配資源后,然后在pool上注冊一個釋放資源的函數,pool?銷毀(清理)的時候,會調用這個函數,釋放資源。例如打開了一個文件,可以在?pool?上注冊一個關閉文件的函數,讓?pool?替你關閉文件。也可以在不銷毀(清理)pool?時,手動的釋放。具體可以看參考apr手冊

APR的核心就是Apache的資源管理(池),我們將在本章的后面部分進行更加詳細的介紹。表3-1列出了APR中的所有模塊。

3-1? APR模塊

名稱

目的

apr_allocator

內存分配,內部使用

apr_atomic

原子操作

apr_dso

動態加載代碼(.so/.dll

apr_env

讀取/設定環境變量

apr_errno

定義錯誤條件和宏

apr_file_info

文件系統對象和路徑的屬性

apr_file_io

文件系統輸入/輸出

apr_fnmatch

文件系統模式匹配

apr_general

初始化/終結,有用的宏

名稱

目的

apr_getopt

命令參數

apr_global_mutex

全局鎖

apr_hash

哈希表

apr_inherit

文件句柄繼承助手

apr_lib

奇數和末端

apr_mmap

內存映射

apr_network_io

網絡輸入/輸出(套接字)

apr_poll

投票

apr_pools

資源管理

apr_portable

APR到本地映射轉換

apr_proc_mutex

進程鎖

apr_random

隨機數

apr_ring

環數據結構和宏

apr_shm

共享內存

apr_signal

信號處理

apr_strings

字符串操作

apr_support

內部支持函數

apr_tables

表格和數組函數

apr_thread_cond

線程條件

apr_thread_mutex

線程鎖

apr_thread_proc

線程和進程函數

apr_thread_rwlock

讀寫鎖

apr_time

時間/日期函數

apr_user

用戶和組ID服務

apr_version

APR版本

apr_want

標準頭文件支持

3-2? APU模塊

名稱

目的

apr_anylock

透明的、任何鎖的封裝

apr_base64

Base-64編碼

apr_buckets

Buckets/Bucket brigade

apr_date

時間字符串解析

apr_dbd

針對SQL數據庫的常用API

apr_dbm

針對DBM數據庫的常用API

apr_hooks

鉤子實現宏

apr_ldap

LDAP授權API

apr_ldap_init

LDAP初始化API,主要應用在和LDAP服務器的初始安全連接

apr_ldap_option

設置LDAP選項的API

apr_ldap_url

解析和處理LDAP URLAPI

apr_md4

MD4編碼

apr_md5

MD5編碼

apr_optional

可選函數

apr_optional_hooks

可選鉤子

apr_queue

線程安全的FIFO隊列

apr_reslist

資源池

apr_rmm

可再定位地址的內存

名稱

目的

apr_sdbm

SDBM

apr_sha1

SHA1編碼

apr_strmatch

字符串模式匹配

apr_uri

URI解析/構造

apr_uuid

用戶標識

apr_xlate

字符集轉換(I18N

apr_xml

XML解析

???

基本的約定

APR和APR-UTIL采用了一些約定,使得它們的API具有同質性,并且易于使用。

3.3.1??參考手冊:API文檔和Doxygen

APR和APU在代碼層都有非常好的文檔。每一個公開函數和數據類型都在定義它們的頭文件中進行了注釋,使用了doxygen?友好的格式。那些頭文件,或者doxygen生成的文檔,為程序員提供了完整的API參考手冊。如果你安裝了doxygen,那么就可以通過make dox命令從源代碼中生成你自己版本的APR參考手冊。

3.3.2??命名空間

所有的APR和APU的公開接口都使用了字符串前綴“apr_”(數據類型和函數)和“APR_”(宏),這就為APR定義了一個“保留”的命名空間。

在APR命名空間中,絕大部分的APR和APU模塊使用了二級命名空間。這個約定通常基于正在討論的那個模塊的名字。例如,模塊apr_dbd中的所有函數使用字符串“apr_dbd_”前綴。有時候使用一個明顯的描述性的二級命名空間。例如,在模塊apr_network_io中套接字操作使用“apr_socket_”前綴。

3.3.3??聲明的宏

APR和APU的公開函數使用類似于APR_DECLARE、APU_DECLARE和APR_ DECLARE_NONSTD的宏進行聲明。例如:

APR_DECLARE(apr_status_t) apr_initialize(void);

在很多的平臺上,這是一個空聲明,并且擴展為

apr_status_t apr_initialize(void);

例如在Windows的Visual C++平臺上,需要使用它們自己的、非標準的關鍵字,例如“_dllexport”來允許其他的模塊使用一個函數,這些宏就需要擴展以適應這些需要的關鍵字。

3.3.4? apr_status_t和返回值

在APR和APU中廣泛采用的一個約定是:函數返回一個狀態值,用來為調用者指示成功或者是返回一個錯誤代碼。這個類型是apr_status_t,在apr_errno.h中定義,并賦予整數值。因此一個APR函數的常見原型就是:

APR_DECLARE(apr_status_t) apr_do_something(…function args…);

返回值應當在邏輯上進行判斷,并且實現一個錯誤處理函數(進行回復或者對錯誤進行進一步的描述)。返回值APR_SUCCESS意味著成功,我們通常可以用如下的方式進行錯誤處理結構:

apr_status_t rv;
...
rv = apr_do_something(... args ...);
if (rv != APR_SUCCESS) {
/*?記錄一個錯誤?*/
return rv;
}

有時候我們可能需要做得更多。例如,如果do_something是一個非閉塞的I/O操作并且返回APR_EAGAIN,我們可能需要重試這個操作。
有些函數返回一個字符串(char *或者const char *)、一個void *或者void。這些函數就被認為在沒有失敗條件或者在錯誤發生時返回一個空指針。

3.3.5??條件編譯

本質上說,APR的一些特色可能并不是每個平臺都支持的。例如,FreeBSD在5.x版本之前并沒有適合Apache的本地線程實現,因此線程在APR中就不被支持(除非編譯時手動設置相應的操作)。

為了在這種情況下應用程序依然能夠工作,APR為這些情況提供了APR_HAS_*宏。如果一個應用處于這種情況,它應當使用這些宏進行條件編譯。例如,一個模塊執行了一個操作,這個操作可能導致在多線程環境下的競爭條件,那么它就可能使用以下的方式。

#if APR_HAS_THREADS
rv = apr_thread_mutex_lock(mutex);
if (rv != APR_SUCCESS) {
/*?記錄一個錯誤?*/
/*?放棄關鍵的操作*/
}
#endif

??? /* ...?在這里執行關鍵代碼... */

#if APR_HAS_THREAD
apr_thread_mutex_unlock(mutex);
#endif

?

二、apr_pool內存池。

pool本身并不直接從物理內存中分配或釋放,而是通過allocator(內存分配器)來統一管理,可以為新池創建新的allocator(內存分配器),但通常使用默認的全局allocator(內存分配器),這樣更有助于統一的內存管理。pool采用的是樹形的結構,在初始化內存池(apr_pool_initialize)時,建立根池,和全局allocator(內存分配器),以后建立的都是根結點的子孫結點可以從pool中分配任何大小的內存塊,但釋放的單位為pool,就是說pool釋放之前,從pool分配出的內存不能單獨釋放,看起來好像有點浪費。這里要注意的是,有些分配的內存塊,清除時有特別操作,這樣就需要要帶清除函數,在分配之后用apr_pool_cleanup_register注冊清除時用的函數。特殊的,如果內存塊里是線程對象,也不能用一般的清除函數,應該用apr_pool_note_subprocess注冊清除操作。

apr_pool中主要有3個對象,allocator、pool、block。pool從allocator申請內存,pool銷毀的時候把內存歸還allocator,allocator銷毀的時候把內存歸還給系統,allocator有一個owner成員,是一個pool對象,allocator的owner銷毀的時候,allocator被銷毀。在apr_pool中并無block這個單詞出現,這里大家可以把從pool從申請的內存稱為block,使用apr_palloc申請block,block只能被申請,沒有釋放函數,只能等pool銷毀的時候才能把內存歸還給allocator,用于allocator以后的pool再次申請。

常見函數:

對系統內存池初始化,全局的,一個進程只要初始化一次

apr_status_t?????apr_pool_initialize (void)

銷毀內存池對象,及內部的結構和子內存池

void?????????apr_pool_terminate (void)

?

創建一個新的內存池

apr_status_t?????apr_pool_create_ex (apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, apr_allocator_t *allocator)

創建一個新的內存池,apr_pool_create_ex的使用默認參數簡化版

apr_status_t?????apr_pool_create (apr_pool_t **newpool, apr_pool_t *parent)

獲取內存池使用的內存分配器

apr_allocator_t *?????apr_pool_allocator_get (apr_pool_t *pool)

清除一個內存池的內容,清除后內容為空,但可以再使用

void?????????????apr_pool_clear (apr_pool_t *p)

釋構一個內存池

void?????????????apr_pool_destroy (apr_pool_t *p)

?

從池中分配內存

void *?????????????apr_palloc (apr_pool_t *p, apr_size_t size)

從池中分配內存,并將分配出來的內存置0

void *?????????????apr_pcalloc (apr_pool_t *p, apr_size_t size)

?

設置內存分配出錯時的調用函數

void?????????????apr_pool_abort_set (apr_abortfunc_t abortfunc, apr_pool_t *pool)

獲取內存分配出錯時的調用函數

apr_abortfunc_t?????apr_pool_abort_get (apr_pool_t *pool)

?

獲取池的父池

apr_pool_t *?????apr_pool_parent_get (apr_pool_t *pool)

?

判斷a是否是b的祖先

int?????????????apr_pool_is_ancestor (apr_pool_t *a, apr_pool_t *b)

?

為內存池做標簽

void?????????????apr_pool_tag (apr_pool_t *pool, const char *tag)

?

設置與當前池關聯的數據

apr_status_t?????apr_pool_userdata_set (const void *data, const char *key, apr_status_t(*cleanup)(void *), apr_pool_t *pool)

設置與當前池關聯的數據,與apr_pool_userdata_set類似,但內部不拷貝數據的備份,如常量字符串時就有用

apr_status_t?????apr_pool_userdata_setn (const void *data, const char *key, apr_status_t(*cleanup)(void *), apr_pool_t *pool)

獲取與當前池關聯的數據

apr_status_t?????apr_pool_userdata_get (void **data, const char *key, apr_pool_t *pool)

注冊內存塊的清除函數,每塊銷毀時要特別處理的都要注冊下,在cleanups里加入一個項

void?????????????apr_pool_cleanup_register (apr_pool_t *p, const void *data, apr_status_t(*plain_cleanup)(void *), apr_status_t(*child_cleanup)(void *))

刪除內存塊的清除函數,從cleanups里移除一個項,放入free_cleanups中

void?????????????apr_pool_cleanup_kill (apr_pool_t *p, const void *data, apr_status_t(*cleanup)(void *))

用新的child_cleanup,替換原來老的child_cleanup

void?????????????apr_pool_child_cleanup_set (apr_pool_t *p, const void *data, apr_status_t(*plain_cleanup)(void *), apr_status_t(*child_cleanup)(void *))

執行內存塊的清除函數,進從清除函數的隊列cleanups中刪除

apr_status_t?????apr_pool_cleanup_run (apr_pool_t *p, void *data, apr_status_t(*cleanup)(void *))

一個空的內存塊清除函數

apr_status_t?????apr_pool_cleanup_null (void *data)

執行所有的子清除函數child_cleanup

void?????????????apr_pool_cleanup_for_exec (void)

?

帶調試信息內存池函數,功能跟上面的一樣,只是多了調試信息

apr_status_t?????apr_pool_create_ex_debug (apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, apr_allocator_t *allocator, const char *file_line)

void?????????????apr_pool_clear_debug (apr_pool_t *p, const char *file_line)

void?????????????apr_pool_destroy_debug (apr_pool_t *p, const char *file_line)

void *?????????????apr_palloc_debug (apr_pool_t *p, apr_size_t size, const char *file_line)

void *?????????????apr_pcalloc_debug (apr_pool_t *p, apr_size_t size, const char *file_line)

?

????一般可以不調用創建allocator的函數,而是使用的默認全局allocator。但是apr_pool提供了一系列函數操作allocator,可以自己調用這些函數:

apr_allocator_create

apr_allocator_destroy

apr_allocator_alloc

apr_allocator_free??創建銷毀allocator

apr_allocator_owner_set

apr_allocator_owner_get??設置獲取owner

apr_allocator_max_free_set?設置pool銷毀的時候內存是否直接歸還到操作系統的閾值

apr_allocator_mutex_set

apr_allocator_mutex_get??設置獲取mutex,用于多線程

apr_pool的一個大缺點就是從池中申請的內存不能歸還給內存池,只能等pool銷毀的時候才能歸還。為了彌補這個缺點,apr_pool的實際使用中,可以申請擁有不同生命周期的內存池。

?

三、實例

#include?"stdafx.h"

#include?"apr_pools.h"

#include?<new>

#pragma?comment(lib,"libapr-1.lib")

?

int?main(int?argc,?char*?argv[])

{

????apr_pool_t?*root;

????apr_pool_initialize();//初始化全局分配子(allocator),并為它設置mutext,以用于多線程環境,初始化全局池,指定全局分配子的owner是全局池

????apr_pool_create(&root,NULL);//創建根池(默認父池是全局池),根池生命期為進程生存期。分配子默認為全局分配子

????{

????????apr_pool_t?*child;

????????apr_pool_create(&child,root);//創建子池,指定父池為root。分配子默認為父池分配子

???????void?*pBuff=apr_palloc(child,sizeof(int));//從子池分配內存

???????int?*pInt=new?(pBuff)??int(5);//隨便舉例下基于已分配內存后,面向對象構造函數的調用。

????????printf("pInt=%d/n",*pInt);

???????{

???????????typedef?struct?StudentInfo{

???????????????char?szName[20];

???????????????bool?nSex;

???????????};

?

???????????apr_pool_t?*grandson;

????????????apr_pool_create(&grandson,root);

???????????void?*pBuff2=apr_palloc(grandson,sizeof(StudentInfo));

???????????StudentInfo?*pSI=new?(pBuff2)??StudentInfo();

???????????strcpy(pSI->szName,"zhangsan");

???????????pSI->nSex?= 1;

???????????printf("Name=%s,sex=%d/n",pSI->szName,pSI->nSex);???

?

???????????apr_pool_destroy(grandson);

???????}

????????apr_pool_destroy(child);//釋放子池,將內存歸還給分配子

????}

????apr_pool_destroy(root);//釋放父池,

????apr_pool_terminate();//釋放全局池,釋放全局allocator,將內存歸還給系統

????return?0;

}

?

?

總結

以上是生活随笔為你收集整理的不定长内存池之apr_pool的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩一级在线观看视频 | 欧美精品二区三区 | 免费毛片在线播放免费 | 国产又粗又猛又黄 | 国产大片91 | 一区不卡av | 性欢交69精品久久久 | 亚洲国产看片 | 日韩区在线 | av小说在线 | 穿扒开跪着折磨屁股视频 | 日韩av综合网 | 男女操网站 | 日韩视频成人 | 欧美在线一二三四区 | 一级片视频免费观看 | 女人扒开屁股让男人桶 | 精品人妻av一区二区 | 国产精品久久一 | 日本调教电影 | 一区二区三区伦理 | 久久av高潮av无码av喷吹 | 在线天堂网 | 欧美爱爱爱| 99riav国产| 日本无遮羞调教打屁股网站 | 手机看片日韩国产 | 色综合久久天天综合网 | 五月婷婷激情综合 | 鲁一鲁色一色 | 成人一区二区在线观看 | 人妻熟女一区二区三区 | 日本老熟妇毛茸茸 | 经典三级在线视频 | 无码精品国产一区二区三区 | 91九色视频 | 在线成人观看 | 中文在线字幕免费观看 | 97超碰人人 | 男生插女生的视频 | 综合五月网 | 一区二区欧美视频 | 亚洲伦理一区二区三区 | 国产有码在线观看 | 人妻一区二区三区四区五区 | 日日夜夜艹 | 午夜精品福利一区二区蜜股av | 一区二区三区在线免费播放 | 青青草午夜 | 超碰在线播放97 | gai免费观看网站外网 | 91蜜桃臀久久一区二区 | 免费精品久久 | 免费看的黄网站 | 艳妇乳肉豪妇荡乳 | 久久久久久91香蕉国产 | 欧美日韩精品一区二区三区视频播放 | 国产激情图片 | 男人日女人网站 | 无遮挡国产 | 亚洲中文字幕在线一区 | 美女露胸露尿口 | 粉嫩视频在线观看 | 欧美午夜精品理论片 | 国产精品字幕 | 国产精品亚洲二区在线观看 | 亚洲黄色中文字幕 | www.中文字幕.com | 黄色片久久久 | 99热这里只有精品18 | 国产性猛交xx乱 | 黄色美女片 | 色哟哟免费观看 | 亚洲调教| 尤物视频在线观看国产性感 | 黄色在线观看网站 | 男人添女人囗交视频 | 男人午夜影院 | 98色| 一级小毛片| 国产精品久久久久久久久久久久久久久久久 | 献给魔王伊伏洛基亚吧动漫在线观看 | 老色鬼av| 国产视频一区二区三区在线 | 蜜臀99久久精品久久久久久软件 | xxxx.国产| 国产一区欧美一区 | 伦理片久久 | 欧美日韩国产亚洲一区 | 貂蝉被到爽流白浆在线观看 | 中文字幕久久一区 | 精品视频免费播放 | av有声小说一区二区三区 | 中文在线字幕免费观看电 | 激烈娇喘叫1v1高h糙汉 | av天天堂| 原神女裸体看个够无遮挡 | 山村淫强伦寡妇 | 91亚洲精品在线观看 |