코드 테스트 메모리 유출

【 성명: 판권 소유, 전재 환영, 상업 용도 로 사용 하지 마 십시오. 연락처: feixiaoxixing @ 163. com]
    우리 가 개인 적 으로 프로 그래 밍 하 는 과정 에서 메모리 유출 은 메모리 유출 처럼 각종 기묘 한 문 제 를 일 으 키 지 는 않 지만 그 위해 도 무시 할 수 없다.한편, 메모리 의 유출 로 인해 우리 의 소프트웨어 는 운영 과정 에서 점점 더 많은 메모 리 를 차지 하고 자원 을 차지 하 며 제때에 정리 하지 못 해서 우리 프로그램의 효율 이 점점 낮 아 질 것 이다.다른 한편, 그것 은 우리 사용자 의 체험 에 영향 을 주 고 시장의 경 쟁 력 을 잃 게 될 것 이다.
    흔히 볼 수 있 는 메모리 유출 은 다음 과 같다.
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) 코드 에서 노드 를 삭제 하고 추가 할 때 다 중 프로 세 스 의 상황 을 고려 하지 않 고 상호 배척 자물쇠 나 신 호 량 으로 보호 하 는 것 을 고려 해 야 한다.
(전문 완료)

좋은 웹페이지 즐겨찾기