코드 테스트 메모리 유출
우리 가 개인 적 으로 프로 그래 밍 하 는 과정 에서 메모리 유출 은 메모리 유출 처럼 각종 기묘 한 문 제 를 일 으 키 지 는 않 지만 그 위해 도 무시 할 수 없다.한편, 메모리 의 유출 로 인해 우리 의 소프트웨어 는 운영 과정 에서 점점 더 많은 메모 리 를 차지 하고 자원 을 차지 하 며 제때에 정리 하지 못 해서 우리 프로그램의 효율 이 점점 낮 아 질 것 이다.다른 한편, 그것 은 우리 사용자 의 체험 에 영향 을 주 고 시장의 경 쟁 력 을 잃 게 될 것 이다.
흔히 볼 수 있 는 메모리 유출 은 다음 과 같다.
void process(int size)
{
char* pData = (char*)malloc(size);
/* other code */
return; /* forget to free pData */
}
위의 그림 에서 보 듯 이 우 리 는 함수 process 를 처리 하 는 과정 에서 매번 메모리 에 대해 신청 을 해 야 하지만 함수 가 끝 날 때 방출 되 지 않 았 다.만약 이러한 코드 가 업무 측면 에 나타난다 면 결 과 는 상상 하기 어렵다.예 를 들 어 서버 가 1 초 에 100 명의 사용자 의 동시 방문 을 받 아야 한다 면 모든 사용자 가 온 데 이 터 는 로 컬 신청 메모리 가 다시 저장 되 어야 합 니 다.처리 가 끝 난 후에 메모리 가 잘 풀 리 지 않 으 면 서버 에서 사용 할 수 있 는 물리 적 메모리 가 점점 줄 어 들 것 입 니 다.일단 특정한 임계 점 에 도달 한 후에 운영 체 제 는 내부 와 외부 에 저 장 된 스케줄 을 통 해 우리 가 새로운 메모 리 를 신청 하 는 수 요 를 만족 시 켜 야 한다. 이것 은 다른 한편 으로 는 서버 서비스의 질 을 떨 어 뜨 릴 것 이다.메모리 유출 의 위 해 는 말 하지 않 아 도 알 수 있 지만 메모리 유출 을 찾 는 것 은 어렵 고 복잡 한 일이 다.버그 를 해결 하 는 것 은 매우 간단 한 일이 지만 버그 의 출처 를 찾 는 것 은 매우 힘 든 일이 다.따라서 코드 를 작성 할 때 메모리 유출 을 찾 는 작업 을 중요 한 위치 에 놓 을 필요 가 있다.그렇다면 이 문 제 를 해결 할 방법 은 없 을 까?
메모리 유출 을 해결 하려 면 다음 두 가 지 를 해 야 합 니 다.
(1) 메모리 가 어느 함수 에서 신청 되 었 는 지 기록 해 야 합 니 다. 구체 적 인 파일 의 줄 수 는 얼마 입 니까?
(2) 메모리 가 언제 풀 려 야 합 니까?
첫 번 째 조건 을 완성 하 는 것 은 사실 결코 어렵 지 않다.우 리 는 노드 의 방법 으로 우리 가 신청 한 메모 리 를 기록 할 수 있다.
a) 노드 의 데이터 구조 설정
typedef struct _MEMORY_NODE
{
char functionName[64];
int line;
void* pAddress;
struct _MEMORY_NODE* next;
}MEMORY_NODE;
그 중에서 functionName 은 함수 이름, line 은 줄 수 를 기록 하고 pAddress 는 분 배 된 주 소 를 기록 하 며 next 는 다음 메모리 노드 를 기록 합 니 다.b) 메모리 할당 함수 수정
업무 측면의 malloc 에 함수 수정 을 하고 다음 매크로 문 구 를 추가 합 니 다.
#define malloc(param) MemoryMalloc(__FUNCTION__, __LINE__, param)
말뚝 함수 옆 에 아래 코드 를 쓰 세 요.
void* MemoryMalloc(const char* name, int line, int size)
{
void* pData = (void*)malloc(size);
MEMORY_NODE* pMemNode = NULL;
if(NULL == pData) return NULL;
memset((char*)pData, 0, size);
pMemNode = (MEMORY_NODE*)malloc(sizeof(MEMORY_NODE));
if(NULL == pMemNode){
free(pData);
return NULL;
}
memset((char*)pMemNode, 0, sizeof(MEMORY_NODE));
memmove(pMemNode->functionName, name, strlen(name));
pMemNode->line = line;
pMemNode->pAddress = pData;
pMemNode->next = NULL;
add_memory_node(pMemNode);
return pData;
}
메모리 의 분배 과정 에서 노드 의 추가 도 언급 되 었 기 때문에 우 리 는 아래 의 코드 를 추가 해 야 한다.
static MEMORY_NODE* gMemNode = NULL;
void add_memory_node(MEMORY_NODE* pMemNode)
{
MEMORY_NODE* pNode = gMemNode;
if(NULL == pMemNode) return;
if(NULL == gMemNode){
gMemNode = pMemNode;
return;
}
while(NULL != pNode->next){
pNode = pNode->next;
}
pNode->next = pMemNode;
return;
}
글 에서 gMemNode 는 모든 메모리 노드 의 루트 노드 를 표시 합 니 다. 우 리 는 malloc 과정 을 추가 할 때마다 메모리 노드 를 기록 합 니 다.기록 과정 에서 우 리 는 malloc 를 호출 하 는 함수 이름과 구체 적 인 파일 줄 수 를 기록 할 것 이다. 이것 은 주로 우리 가 뒤에서 고장 포 지 셔 닝 을 할 때 더욱 잘 찾 을 수 있 도록 하기 위해 서 이다.첫 번 째 조건 을 완성 한 후에 우 리 는 두 번 째 조건 을 완성 해 야 한다.
a) 메모리 가 언제 방출 되 는 지 는 우리 가 함수 에서 어떻게 실현 되 는 지 에 달 려 있 습 니 다. 그러나 우 리 는 테스트 사례 를 작성 할 때 메모리 가 방출 되 었 는 지 알 아야 합 니 다. 예 를 들 어 테스트 사례 가 모두 끝나 면 assert (gMemNode = NULL) 를 믿 을 이유 가 있 습 니 다.
b) 메모리 가 풀 릴 때 우 리 는 무엇 을 해 야 합 니까?노드 의 추가 와 마찬가지 로 우 리 는 메모리 에서 방출 할 때 free 가 지정 한 메모리, free 노드, free 노드 의 메모리 가 필요 합 니 다. 다음은 방출 할 때 우리 가 해 야 할 작업 입 니 다.
업무 측면의 free 함 수 를 수정 하고 다음 매크로 코드 를 추가 합 니 다.
#define free(param) MemoryFree(param)
파일 함수 옆 에 아래 코드 를 입력 하 십시오:
void MemoryFree(void* pAddress)
{
if(NULL == pAddress) return;
delete_memory_node(pAddress);
free(pAddress);
}
메모 리 를 삭제 할 때 노드 를 삭제 하고 노드 의 메모 리 를 삭제 해 야 합 니 다.
void delete_memory_node(void* pAddress)
{
MEMORY_NODE* pHead = gMemNode;
MEMORY_NODE* pMemNode = gMemNode;
while(NULL != pMemNode){
if(pAddress == pMemNode->pAddress)
break;
pMemNode = pMemNode->next;
}
if(NULL == pMemNode) {
assert(1 == 0);
return;
}
while(pMemNode != pHead->next){
pHead = pHead->next;
}
if(pMemNode == gMemNode){
gMemNode = gMemNode->next;
}else{
pHead->next = pMemNode->next;
}
free(pMemNode);
return;
}
위의 작은 코드 의 도움 이 있 습 니 다. 테스트 사례 를 작성 할 때 함수 가 실 행 된 후에 메모리 노드 가 비어 있 는 지 판단 하 는 방법 으로 메모리 가 풀 렸 는 지 여 부 를 판단 할 수 있 습 니 다.만약 메모리 가 방출 되 지 않 았 다 면 우 리 는 노드 의 정 보 를 통 해 우리 가 어디에서 오류 가 발생 했 는 지 도 울 수 있 지만 이 방법 은 두 가지 단점 이 있다.
(1) 캐 시 상황 을 고려 하지 않 고 많은 메모리 가 분 배 된 후에 함수 에서 바로 방출 되 지 않 고 캐 시 풀 에 넣 어 다음 호출 을 기다 리 고 있 습 니 다. 이 는 우리 가 정확하게 파악 하고 판단 해 야 합 니 다.
(2) 코드 에서 노드 를 삭제 하고 추가 할 때 다 중 프로 세 스 의 상황 을 고려 하지 않 고 상호 배척 자물쇠 나 신 호 량 으로 보호 하 는 것 을 고려 해 야 한다.
(전문 완료)
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.