亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区
Chinaunix
標(biāo)題:
線程創(chuàng)建子線程,線程退出時,釋放了內(nèi)存,但是TOP中只看到有一般的內(nèi)存被釋放了
[打印本頁]
作者:
korpus
時間:
2014-02-12 14:40
標(biāo)題:
線程創(chuàng)建子線程,線程退出時,釋放了內(nèi)存,但是TOP中只看到有一般的內(nèi)存被釋放了
架構(gòu)是這樣的。
主進(jìn)程先初始化了一個線程池A,當(dāng)其中一個線程接收到任務(wù)的時候,就會去創(chuàng)建幾個子線程B來處理任務(wù)。(該A1線程使用pthread_jion等待子線程B退出,子線程用pthread_exit退出)。在子線程B中,使用了malloc函數(shù)連續(xù)分配了2段內(nèi)存。任務(wù)處理完后,在退出pthread_exit前,釋放他們。
其中的異,F(xiàn)象是這樣的,如果我在子線程B中加了日志打印的函數(shù),那么所有子線程退出時,上面申請的兩個連續(xù)內(nèi)存有一半的大小在top中顯示為未釋放(實(shí)際上,已經(jīng)釋放了,我向那2段內(nèi)存中memcpy程序core了)。如果我在子線程B中不加日志打印函數(shù),就不會有這個現(xiàn)象。
日志打印函數(shù),檢查過,沒有什么問題。
#define LOG_INFO Log_SysInfo(LOG_LEVEL_INFO,__FILE__,__LINE__),Log_Msg
void Log_SysInfo(const int iLogLevel, const char *pszFileName, const int iNum)
{
int i = 0;
char szLogTime[30];
// 加一個寫日志的線程鎖
pthread_mutex_lock(&g_WriteLog);
memset(szLogTime, 0, sizeof(szLogTime));
memset(g_szLogHead, 0, sizeof(g_szLogHead));
g_iLogLevel = iLogLevel;
// 如果設(shè)置的日志級別小直接返回
if(g_iSetLogLevel < g_iLogLevel)
{
return;
}
Log_Check();
timev_GetLogTime(szLogTime);
snprintf(g_szLogHead, sizeof(g_szLogHead), "%s %s L=%d T=%ld E=%d ", szLogTime, pszFileName,
iNum, pthread_self(), errno);
switch(iLogLevel)
{
case LOG_LEVEL_ERROR:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[ERROR] ");
break;
case LOG_LEVEL_WARN:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[WARN] ");
break;
case LOG_LEVEL_DEBUG:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[DEBUG] ");
break;
case LOG_LEVEL_INFO:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[INFO] ");
break;
case LOG_LEVEL_ALL:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[ALL] ");
break;
default:
break;
}
}
void Log_Msg(const char *format, ...)
{
FILE *fp;
va_list args;
int olderrno;
//char szContext[1024*10]; // 分配10K的臨時變量空間,如果用內(nèi)存分配會不會影響性能
int i;
// 如果設(shè)置的日志級別小,則直接返回
if(g_iSetLogLevel < g_iLogLevel)
{
pthread_mutex_unlock(&g_WriteLog);
return;
}
olderrno = errno;
//memset(szContext, 0, sizeof(szContext));
if(NULL != (fp = fopen(g_szLogFile, "a+")))
{
fprintf(fp, "%s", g_szLogHead);
va_start(args, format);
// fprintf(fp, "%s\n", szContext);
vfprintf(fp, format, args);
// fflush(fp);
va_end(args);
fprintf(fp, "%s", "\n");
fclose(fp);
}
else
{
printf("fopen error, errno=%d, file=%s\n", errno, g_szLogFile);
perror("fopen");
//printf("context1 [%s], file[%s:%d] \n", szContext, __FILE__, __LINE__);
}
errno = olderrno;
pthread_mutex_unlock(&g_WriteLog);
}
復(fù)制代碼
作者:
korpus
時間:
2014-02-12 14:45
這個是子線程的代碼,就算是這樣,先連續(xù)申請兩段內(nèi)存,然后釋放,top中顯示就沒有釋放完。 如果我在pReadMemory申請后,再釋放,pWriteMemory申請后,再釋放就是正常的。搞不懂是什么意思,求大哥大姐幫幫忙!
void *trans_SingleThread(void *pData)
{
int iRet;
MultTransData *pMultTransData = (MultTransData *)pData;
MMapData *pMMapData = NULL;
ListNode *pTemp = NULL;
void *pReadMemory = NULL;
void *pWriteMemory = NULL;
MMapData *pFirstSection = NULL;
pTemp = pMultTransData->m_pMMapDataList;
pFirstSection = (MMapData *)pTemp->pData;
// 為寫空間分配內(nèi)存地址
pWriteMemory = ufs_MallocMemory(pFirstSection->m_lWriteTotalSize);
if(NULL == pWriteMemory)
{
LOG_ERROR("Malloc Memory Failure!");
ufs_vFreeNormalMemory(&pReadMemory);
iRet = RT_FAILURE;
pthread_exit((void *)&iRet);
}
// 為讀空間分配內(nèi)存地址
pReadMemory = ufs_MallocMemory(pFirstSection->m_lReadTotalSize);
if(NULL == pReadMemory)
{
LOG_ERROR("Malloc Memory Failure!");
iRet = RT_FAILURE;
pthread_exit((void *)&iRet);
}
LOG_DEBUG("Thread Will Quit");
ufs_vFreeNormalMemory(&pReadMemory);
ufs_vFreeNormalMemory(&pWriteMemory);
pthread_exit((void *)&iRet);
}
復(fù)制代碼
作者:
korpus
時間:
2014-02-12 16:11
求幫助!有沒有哪個可以幫忙看看呢
作者:
gaojl0728
時間:
2014-02-12 16:43
本帖最后由 gaojl0728 于 2014-02-12 16:45 編輯
回復(fù)
3#
korpus
1. 能不能把LOG_DEBUG的代碼貼出來。
2. 你是看top的哪一個字段?
3. 你說“我向那2段內(nèi)存中memcpy程序core了”, 什么叫core了, 是crash了嗎?
4. crash了, 不一定能證明就是釋放了, 把memcpy的代碼貼出來
作者:
korpus
時間:
2014-02-12 16:56
回復(fù)
4#
gaojl0728
你好,謝謝你的關(guān)注,
1 LOG_DEBUG,貼出來了 ,就在第一個代碼里面的
2 top的res字段
3 意思好像沒有表達(dá)清楚,意思是,在我free那2段內(nèi)存后,為了檢查是否真的釋放了,然后向釋放的內(nèi)存memcpy內(nèi)容,然后程序crash了
4 memcpy(pReadMemory, "12345", 5);
作者:
gaojl0728
時間:
2014-02-12 17:10
1. 你第一行貼的是LOG_INFO, 我想看看LOG_DEBUG。
2. ufs_vFreeNormalMemory傳遞的為什么是雙重指針,難道會把參數(shù)設(shè)置為NULL?
如果是寫NULL的話,你就不需要memcpy測試了, 直接看看是不是NULL就行了
3. 能不能把ufs_MallocMemory和ufs_vFreeNormalMemory的代碼貼出來看看?
如果實(shí)現(xiàn)是用的malloc和free, 那內(nèi)存可能被glibc的內(nèi)存池回收了,并沒有還給內(nèi)核。把代碼貼出來看看吧
4. pFirstSection->m_lWriteTotalSize和pFirstSection->m_lReadTotalSize的大小多少?
作者:
gaojl0728
時間:
2014-02-12 17:11
回復(fù)
5#
korpus
1. 你第一行貼的是LOG_INFO, 我想看看LOG_DEBUG。
2. ufs_vFreeNormalMemory傳遞的為什么是雙重指針,難道會把參數(shù)設(shè)置為NULL?
如果是寫NULL的話,你就不需要memcpy測試了, 直接看看是不是NULL就行了
3. 能不能把ufs_MallocMemory和ufs_vFreeNormalMemory的代碼貼出來看看?
如果實(shí)現(xiàn)是用的malloc和free, 那內(nèi)存可能被glibc的內(nèi)存池回收了,并沒有還給內(nèi)核。把代碼貼出來看看吧
4. pFirstSection->m_lWriteTotalSize和pFirstSection->m_lReadTotalSize的大小多少?
作者:
korpus
時間:
2014-02-12 17:37
回復(fù)
7#
gaojl0728
你好,首先謝謝您哈。
1. 你第一行貼的是LOG_INFO, 我想看看LOG_DEBUG。
#define LOG_ERROR Log_SysInfo(LOG_LEVEL_ERROR,__FILE__,__LINE__),Log_Msg
#define LOG_WARN Log_SysInfo(LOG_LEVEL_WARN,__FILE__,__LINE__),Log_Msg
#define LOG_INFO Log_SysInfo(LOG_LEVEL_INFO,__FILE__,__LINE__),Log_Msg
#define LOG_DEBUG Log_SysInfo(LOG_LEVEL_DEBUG,__FILE__,__LINE__),Log_Msg
復(fù)制代碼
2. ufs_vFreeNormalMemory傳遞的為什么是雙重指針,難道會把參數(shù)設(shè)置為NULL?
如果是寫NULL的話,你就不需要memcpy測試了, 直接看看是不是NULL就行了
是的,就是為了將其置為空,打印過,釋放后,確實(shí)也是NULL
3.函數(shù)如下
void *ufs_MallocMemory(const long lSize)
{
void *pAddr = NULL;
if(lSize <= 0)
{
LOG_ERROR("malloc memory size less than zero");
return NULL;
}
pAddr = malloc(lSize);
if(NULL == pAddr)
{
LOG_ERROR("malloc memory size error!, malloc size(%d)", lSize);
return NULL;
}
memset(pAddr, 0, lSize);
return pAddr;
}
void ufs_vFreeNormalMemory(void **pAddr)
{
// LOG_WARN("TEST MEMORY FREE[%p]", *pAddr);
if(NULL == *pAddr)
return;
else
free(*pAddr);
*pAddr = NULL;
}
復(fù)制代碼
是用的malloc與free,在網(wǎng)上也查了說有可能被glibc回收,但是每次我運(yùn)行一次的時候,內(nèi)存就增加了。
4. pFirstSection->m_lWriteTotalSize和pFirstSection->m_lReadTotalSize的大小多少?
這幾個值是設(shè)定的值,一般在10M以上
再次謝謝哈
作者:
folklore
時間:
2014-02-12 17:59
內(nèi)存的問題我不猜~~
>>
但是每次我運(yùn)行一次的時候,內(nèi)存就增加了。
如果是指進(jìn)程已經(jīng)結(jié)束重跑的話。
就不用擔(dān)心內(nèi)存問題了。
進(jìn)程一結(jié)束,
滲漏的內(nèi)存也會被OS自動回收。
作者:
gaojl0728
時間:
2014-02-12 18:17
本帖最后由 gaojl0728 于 2014-02-12 18:22 編輯
回復(fù)
8#
korpus
glibc只是一個可疑的點(diǎn),但是不確定是不是真的被內(nèi)存池回收而沒換給內(nèi)核了。
看你的代碼沒什么問題, 沒有內(nèi)存泄露, 也沒看到死鎖
如果不是被內(nèi)存池緩存的話,我感覺可能只是一個top的顯示問題
作者:
一只嗡嗡的蒼蠅
時間:
2014-02-12 22:36
gcc和操作系統(tǒng)均有可能有內(nèi)存池。
作者:
korpus
時間:
2014-02-13 08:53
回復(fù)
10#
gaojl0728
就是最奇怪的就是,如果我把
LOG_DEBUG("Thread Will Quit");
這行注釋掉,top命令顯示就是正常的。
作者:
korpus
時間:
2014-02-13 08:55
回復(fù)
9#
folklore
你好,謝謝的你的關(guān)注哈。
進(jìn)程結(jié)束,內(nèi)存是會被回收的,現(xiàn)在是在線程里面。
作者:
korpus
時間:
2014-02-13 09:03
回復(fù)
11#
一只嗡嗡的蒼蠅
你好,謝謝你的關(guān)注。
能不能確認(rèn)這個內(nèi)存池呢
作者:
folklore
時間:
2014-02-13 09:55
上 Valgrind 吧。
作者:
korpus
時間:
2014-02-13 16:18
本帖最后由 korpus 于 2014-02-13 16:23 編輯
我把代碼整理出來了一份可以獨(dú)立編譯
比較奇怪的是如果注釋掉函數(shù) trans_SingleThread
LOG_DEBUG("Thread Will Quit [%ld]", pthread_self());
,釋放回正常,如果沒注釋釋放就不正常了
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <sys/timeb.h>
#include <sys/stat.h>
#include <pthread.h>
typedef enum
{
LOG_LEVEL_ERROR, // only print ERROR log
LOG_LEVEL_WARN, // print ERROR and WARN log
LOG_LEVEL_INFO, // print ERROR, WARN and INFO log
LOG_LEVEL_DEBUG, // print ERROR, WARN, INFO AND DEBUG log
LOG_LEVEL_ALL // print all log, and print full debug log and other informations
}LOG_LEVEL;
static char g_szLogHead[200];
static long g_iSetLogLevel = 3;
static long g_lSetLogSize = 0;
static int g_iLogLevel;
static char g_szLogFile[256]="./test.log";
pthread_mutex_t g_WriteLog = PTHREAD_MUTEX_INITIALIZER;
static char g_szLogPath[128]=".";
static char g_szLogName[128]="test.log";
#define LOG_ERROR Log_SysInfo(LOG_LEVEL_ERROR,__FILE__,__LINE__),Log_Msg
#define LOG_WARN Log_SysInfo(LOG_LEVEL_WARN,__FILE__,__LINE__),Log_Msg
#define LOG_INFO Log_SysInfo(LOG_LEVEL_INFO,__FILE__,__LINE__),Log_Msg
#define LOG_DEBUG Log_SysInfo(LOG_LEVEL_DEBUG,__FILE__,__LINE__),Log_Msg
#define RT_SUCCESS 0
#define RT_FAILURE -1
void Log_Check();
long timel_GetCurrentTime()
{
char szTime[7];
long lCurTime;
struct tm *ptime;
time_t times;
time(×);
ptime = localtime(×);
memset(szTime, 0, sizeof(szTime));
sprintf(szTime, "%02d%02d%02d", ptime->tm_hour, ptime->tm_min, ptime->tm_sec);
lCurTime = atol(szTime);
return lCurTime;
}
long timel_GetCurrentDate()
{
char szDate[9];
long lDate;
struct tm *ptm;
time_t times;
time(×);
ptm = localtime(×);
memset(szDate, 0, sizeof(szDate));
sprintf(szDate, "%d%02d%02d", ptm->tm_year+1900, ptm->tm_mon + 1, ptm->tm_mday);
lDate = atol(szDate);
return lDate;
}
void timev_GetLogTime(char *out_pLogTime)
{
struct timeb ptm;
struct tm *ptmb;
ftime(&ptm);
ptmb = localtime(&ptm.time);
sprintf(out_pLogTime, "%02d-%02d %02d:%02d:%02d.%03d", ptmb->tm_mon+1, ptmb->tm_mday,
ptmb->tm_hour, ptmb->tm_min, ptmb->tm_sec, ptm.millitm);
return ;
}
void Log_SysInfo(const int iLogLevel, const char *pszFileName, const int iNum)
{
int i = 0;
char szLogTime[30];
pthread_mutex_lock(&g_WriteLog);
memset(szLogTime, 0, sizeof(szLogTime));
memset(g_szLogHead, 0, sizeof(g_szLogHead));
g_iLogLevel = iLogLevel;
if(g_iSetLogLevel < g_iLogLevel)
{
return;
}
Log_Check();
timev_GetLogTime(szLogTime);
snprintf(g_szLogHead, sizeof(g_szLogHead), "%s %s L=%d T=%ld E=%d ", szLogTime, pszFileName,
iNum, pthread_self(), errno);
switch(iLogLevel)
{
case LOG_LEVEL_ERROR:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[ERROR] ");
break;
case LOG_LEVEL_WARN:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[WARN] ");
break;
case LOG_LEVEL_DEBUG:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[DEBUG] ");
break;
case LOG_LEVEL_INFO:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[INFO] ");
break;
case LOG_LEVEL_ALL:
sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[ALL] ");
break;
default:
break;
}
}
void Log_Check()
{
struct stat st;
int iRet;
char szLogDate[9];
memset(szLogDate, 0, sizeof(szLogDate));
memcpy(szLogDate, g_szLogFile + strlen(g_szLogPath) + 1, 8);
if(atol(szLogDate) == timel_GetCurrentDate())
{
if(g_lSetLogSize > 0)
{
stat(g_szLogFile, &st);
if(st.st_size / 1024 / 1024 >= g_lSetLogSize)
{
snprintf(g_szLogFile, sizeof(g_szLogFile), "%s/%ld/%s.%ld%s%06d", g_szLogPath,
timel_GetCurrentDate(), g_szLogName,
timel_GetCurrentDate(), "_", timel_GetCurrentTime());
}
}
}
else
{
if(g_lSetLogSize > 0)
{
snprintf(g_szLogFile, sizeof(g_szLogFile), "%s/%ld/%s.%ld%s%06d", g_szLogPath,
timel_GetCurrentDate(), g_szLogName,
timel_GetCurrentDate(), "_", timel_GetCurrentTime());
}
else
{
snprintf(g_szLogFile, sizeof(g_szLogFile), "%s/%ld/%s.%ld", g_szLogPath,
timel_GetCurrentDate(), g_szLogName,
timel_GetCurrentDate());
}
}
}
void Log_Msg(const char *format, ...)
{
FILE *fp;
va_list args;
int olderrno;
int i;
if(g_iSetLogLevel < g_iLogLevel)
{
pthread_mutex_unlock(&g_WriteLog);
return;
}
olderrno = errno;
if(NULL != (fp = fopen(g_szLogFile, "a+")))
{
fprintf(fp, "%s", g_szLogHead);
va_start(args, format);
vfprintf(fp, format, args);
va_end(args);
fprintf(fp, "%s", "\n");
fclose(fp);
}
else
{
printf("fopen error, errno=%d, file=%s\n", errno, g_szLogFile);
perror("fopen");
}
errno = olderrno;
pthread_mutex_unlock(&g_WriteLog);
}
void *ufs_MallocMemory(const long lSize)
{
void *pAddr = NULL;
if(lSize <= 0)
{
LOG_ERROR("malloc memory size less than zero");
return NULL;
}
pAddr = malloc(lSize);
if(NULL == pAddr)
{
LOG_ERROR("malloc memory size error!, malloc size(%d)", lSize);
return NULL;
}
memset(pAddr, 0, lSize);
return pAddr;
}
void ufs_vFreeNormalMemory(void **pAddr)
{
if(NULL == *pAddr)
return;
else
free(*pAddr);
*pAddr = NULL;
}
void *trans_SingleThread(void *pData)
{
int iRet;
void *pReadMemory = NULL;
void *pWriteMemory = NULL;
pWriteMemory = ufs_MallocMemory(20971520);
if(NULL == pWriteMemory)
{
LOG_ERROR("Malloc Memory Failure!");
ufs_vFreeNormalMemory(&pReadMemory);
iRet = RT_FAILURE;
pthread_exit((void *)&iRet);
}
pReadMemory = ufs_MallocMemory(20971520);
if(NULL == pReadMemory)
{
LOG_ERROR("Malloc Memory Failure!");
iRet = RT_FAILURE;
pthread_exit((void *)&iRet);
}
sleep(5);
LOG_DEBUG("Thread Will Quit [%ld]", pthread_self());
ufs_vFreeNormalMemory(&pReadMemory);
ufs_vFreeNormalMemory(&pWriteMemory);
pthread_exit((void *)&iRet);
}
void *pFunc(void *pData)
{
int *iTime = (int *)pData;
long lThreadID[10];
int i;
*iTime = 5;
while(1)
{
for(i = 0; i < *iTime; i ++)
{
if(pthread_create(&lThreadID[i], NULL, trans_SingleThread, NULL) < 0)
{
printf("create error\n");
exit(0);
}
LOG_DEBUG("Success Create Thread [%ld]", lThreadID[i]);
}
for(i = 0; i < *iTime; i ++)
{
pthread_join(lThreadID[i], NULL);
LOG_DEBUG("Thread [%ld] Quit Success!", lThreadID[i]);
}
sleep(*iTime * 5);
}
}
int main(int argc, char *argv[])
{
long lThreadID[10];
int i;
int iRet;
int iThreadNums;
iThreadNums = atoi(argv[1]);
if(iThreadNums > 10 || argc != 2)
{
printf("less than 10, or input 2 args!\n");
exit(0);
}
sleep(5);
for(i = 0; i < iThreadNums; i ++)
{
iRet = pthread_create(&lThreadID[i], NULL, pFunc, &iThreadNums);
if(iRet < 0)
{
printf("error ,exit!\n");
exit(0);
}
LOG_DEBUG("Create Initinal Thread [%ld]", lThreadID[i]);
}
while(1)
{
sleep(2);
}
}
復(fù)制代碼
makefile如下
all:TestMemory
TestMemory:thread.o
cc -o TestMemory thread.o -lpthread
rm -f thread.o
thread.c:thread.o
cc -c thread.c
復(fù)制代碼
作者:
gaojl0728
時間:
2014-02-13 18:38
回復(fù)
16#
korpus
抓了個strace看了下, LOG_DEBUG存在的時候Glibc沒有釋放那20M內(nèi)存給內(nèi)核。 要想知道詳細(xì)的原因只能看glibc了, 可惜glibc代碼的可讀性太差, 不好看啊
作者:
korpus
時間:
2014-02-14 10:02
回復(fù)
17#
gaojl0728
你好,你用strace怎么看的呢?
如果glibc沒有返回給系統(tǒng),正常嗎?
作者:
gaojl0728
時間:
2014-02-14 10:42
回復(fù)
18#
korpus
strace -f -p "pid of your program"能看到程序調(diào)用的系統(tǒng)調(diào)用, 對于大于128K的內(nèi)存分配, glibc會調(diào)用mmap/munmap/madvise分配釋放內(nèi)存,
你的程序分別分配了兩塊20M的內(nèi)存,然后分別釋放掉:
1. 沒有LOG_DEBUG的時候, 一塊20M內(nèi)存是通過munmap釋放掉的,另一塊20M是madvise釋放掉的。
2. 有LOG_DEBUG的時候, 一塊20M內(nèi)存是通過munmap釋放掉的, 另一塊沒有釋放被glibc 回收緩存了。
通常內(nèi)存池會回收并緩存釋放的內(nèi)存而不歸還給內(nèi)核,這是正常的行為,不是內(nèi)存泄露。
要想知道原因只能看glibc的源代碼, 可能pthread的相關(guān)函數(shù)做了某些特殊處理。
作者:
korpus
時間:
2014-02-14 11:35
回復(fù)
19#
gaojl0728
謝謝你哈。我看看。
作者:
korpus
時間:
2014-02-14 15:25
回復(fù)
19#
gaojl0728
1、你好,你是怎么看到的mmap分配的20M內(nèi)存,munmap\madvise釋放的呢,我感覺我strace -f -p看到的只是主線程的,沒有看到創(chuàng)建的子線程分配情況。
2、這個內(nèi)存如果一直增長,到底正常不呢,會不會影響性能?
歡迎光臨 Chinaunix (http://www.72891.cn/)
Powered by Discuz! X3.2