使用自己的記憶體管理方式
最近做監控展示,接收包,解碼,播放,多畫面短時間輪詢,例如10秒,在頻繁使用申請記憶體和洗掉記憶體的程序中,不可避免產生性能上的損耗,作業系統在無法申請到記憶體時,如果自己的程式沒有判斷申請記憶體是否成功,后面會產生一系列的問題,最好的解決方案是使用自己的記憶體管理方式,
定義幾個資料結構
enum
{
en_emptying = 0,
en_writing,
en_canreadings
};
struct smem
{
char v_status;
char v_i_flag;
char r1;
char r2;
int v_len = 0;
uint32_t v_pts = 0;
uint8_t *v_data = NULL;
};
typedef std::shared_ptr<smem> ptr_smem;
定義記憶體池
包含這樣的資料指標:
1 資料記憶體頭部
2 資料記憶體結尾
3 寫指標
4 讀指標
我們限定只有一個執行緒讀,一個執行緒寫,并且避開讀寫記憶體管理的鎖定,
我們的資料有兩種,一種是資料資訊info,也就是我們需要的記憶體起始,記憶體長度,以及其他附加資料資訊,比如這個包的pts值,這個包的狀態資訊,是否是關鍵幀等等,這些東西我們必須要做記憶體對齊規整,另一種資料就是實際資料,比如h264包,h265包,需要解碼的視頻資料(或者其他資料)
這其中有兩種方式來做這個池,一個是將資料資訊直接寫入記憶體的起始位置,一種是將資料資訊放入佇列,直接放入記憶體池中也是可以的,這種寫法避免了資訊佇列的維護,當然,資訊佇列已經是很小的記憶體了,我們提出兩種方式,可以根據需求選擇,
方式一,寫入記憶體池
v_write 是記憶體寫入地址,每次寫完就往后跳,寫入時首先要知道不能超過剩余的空間,否則要等讀指標結束,或者讓讀指標快速通過,寫入方法:
uint8_t *m = v_write;
*(char*)(m) = (char)en_emptying;
m +=sizeof(char);
*(char*)(m) = (char)0;
m +=sizeof(char)*3;
*(int*)m = 0;
m +=sizeof(int);
*(uint32_t*)m = 0;
以上方法就是將資訊資料寫入記憶體池的資料頭部,然后再寫入資料,這種方式比較考驗程式員的基本功,其實也不推薦,另外一種方式直接寫入佇列中,邏輯清晰,該佇列只是一個小型資料集,不會引起性能波動,
以下使用佇列和記憶體池來存放記憶體
看代碼吧,讀寫指標一定要離開一定的距離,開始時是在一起的,以下代碼已經經過驗證,當然,在使用的時候還是需要一定的技巧的,
struct s_mem_pool
{
//qianbo :just one thread read,one thread write ,otherwise error occur
uint8_t *v_data = NULL;
uint8_t *v_end = NULL;
int v_len = 0;;
uint8_t *v_write = NULL;
uint8_t *v_read = NULL;
QMutex v_mux;
std::atomic_int v_framenum;
std::queue<ptr_smem>v_i;
void init_mem(int memlen)
{
if(v_data!=NULL)
{
if(v_len < memlen)
{
free(v_data);
v_data = NULL;
}
}
v_len = memlen;
if(v_data == NULL)
v_data = (uint8_t*)malloc(memlen);
v_end = v_data + memlen;
v_write = v_data;
v_read = v_data;
v_framenum = 0;
v_mux.lock();
while(!v_i.empty())
{
v_i.pop();
}
v_mux.unlock();
~s_mem_pool()
{
clearqueue();
if(v_data!=NULL)
free(v_data);
}
bool push(uint8_t *data, int len,uint32_t pts,bool i_flag)
{
#define EX_LEN (sizeof(char)*4 +sizeof(int)+sizeof(uint32_t))
#define NEEDLEN (len)
#define WRITE_INFO \
ptr_smem mem = std::make_shared<smem>();\
mem->v_data = v_write;\
mem->v_len = len;\
mem->v_pts = pts;\
mem->v_i_flag = i_flag; \
mem->v_status = en_writing;\
v_mux.lock();\
v_i.emplace(mem);\
v_mux.unlock();
#define WRITE_INFO2 \
uint8_t *m = v_write; \
*(char*)(m) = (char)en_writing; \
m +=1; \
*(char*)(m) = (char)i_flag;\
m +=3; \
*(int*)m = len; \
m +=4; \
*(uint32_t*)m = pts; \
m+= 4;\
v_write = m;
if(v_write >= v_read)
{
if((v_end - v_write) > (long)(NEEDLEN))
{
memcpy(v_write,data,len);
WRITE_INFO
v_write += (NEEDLEN);
v_framenum++;
return true;
}
else // the left mem is not enough
{
//qInfo()<<"left mem is not enough";
if((v_read -v_data) > (long)(NEEDLEN))
{
v_write = v_data;
memcpy(v_write,data,len);
WRITE_INFO
v_write += NEEDLEN;
v_framenum++;
return true; //from the head
}
else
{
qInfo()<<"not enough memory 0 :num"<<v_framenum;
return false;
}
}
}
else //read>write
{
if((v_read - v_write) > (long)(NEEDLEN))
{
memcpy(v_write,data,len);
WRITE_INFO
v_write += (NEEDLEN);
v_framenum++;
//IncNumber();
return true;
}
qInfo()<<"not enough memory 1 clear the buffer the len is "<< NEEDLEN;
return false;
}
}
ptr_smem get()
{
ptr_smem sm = nullptr;
v_mux.lock();
if(!v_i.empty())
{
sm = v_i.front();
v_i.pop();
v_read = sm->v_data;
}
v_mux.unlock();
v_framenum--;
return sm;
int size()
{
return v_framenum;
}
void clearqueue()
{
v_mux.lock();
if(!v_i.empty())
{
v_i.pop();
}
v_mux.unlock();
}
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/385883.html
標籤:其他
