2009-05-12 2 views
10

프로그래밍 언어 : C 플랫폼 : ARM 컴파일러 : ADS 1.2간단한 C 구현으로 메모리 malloc/free를 추적 할 수 있습니까?

내 프로젝트에 간단한 melloc/free 전화를 추적 할 필요가

. 프로그램이 모든 리소스를 할당 할 때 얼마나 많은 힙 메모리가 필요한지에 대한 기본적인 아이디어를 얻을 필요가 있습니다. 따라서 malloc/free 호출에 대한 래퍼를 제공했습니다. 이 래퍼에서 나는 malloc가 호출되는 현재의 메모리 카운트를 증가 할 필요 free가 호출 될 때 그것을 감소. 내가 호출자에서 할당 할 수있는 크기가 같이 malloc 경우는 정직이다. 나는 어딘가에 포인터/크기 매핑을 저장할 필요로 free 경우 처리하는 방법을 궁금해하고있다. 이것이 C인데, 이것을 쉽게 구현할 표준지도가 없습니다.

모든 라이브러리에서 링크하지 않으려 고하므로 * .c/h 구현이 더 좋습니다.

그래서 이미 간단한 구현으로 나를 이끌 수 있는지 궁금합니다. 그렇지 않다면, 이것은 앞으로 나아가고 하나를 구현하려는 동기입니다.

EDIT : 순수하게 디버깅 용이며이 코드는 제품과 함께 제공되지 않습니다.

편집 : Makis의 답변에 따라 초기 구현입니다. 이것에 대한 의견을 보내 주시면 감사하겠습니다.

편집 : 재 작업 구현

#include <stdlib.h> 
#include <stdio.h> 
#include <assert.h> 
#include <string.h> 
#include <limits.h> 

static size_t gnCurrentMemory = 0; 
static size_t gnPeakMemory = 0; 

void *MemAlloc (size_t nSize) 
{ 
    void *pMem = malloc(sizeof(size_t) + nSize); 

    if (pMem) 
    { 
    size_t *pSize = (size_t *)pMem; 

    memcpy(pSize, &nSize, sizeof(nSize)); 

    gnCurrentMemory += nSize; 

    if (gnCurrentMemory > gnPeakMemory) 
    { 
     gnPeakMemory = gnCurrentMemory; 
    } 

    printf("PMemAlloc (%#X) - Size (%d), Current (%d), Peak (%d)\n", 
      pSize + 1, nSize, gnCurrentMemory, gnPeakMemory); 

    return(pSize + 1); 
    } 

    return NULL; 
} 

void MemFree (void *pMem) 
{ 
    if(pMem) 
    { 
    size_t *pSize = (size_t *)pMem; 

    // Get the size 
    --pSize; 

    assert(gnCurrentMemory >= *pSize); 

    printf("PMemFree (%#X) - Size (%d), Current (%d), Peak (%d)\n", 
      pMem, *pSize, gnCurrentMemory, gnPeakMemory); 

    gnCurrentMemory -= *pSize; 

    free(pSize); 
    } 
} 

#define BUFFERSIZE (1024*1024) 

typedef struct 
{ 
    bool flag; 
    int buffer[BUFFERSIZE]; 
    bool bools[BUFFERSIZE]; 
} sample_buffer; 

typedef struct 
{ 
    unsigned int whichbuffer; 
    char ch; 
} buffer_info; 


int main(void) 
{ 
    unsigned int i; 
    buffer_info *bufferinfo; 

    sample_buffer *mybuffer; 

    char *pCh; 

    printf("Tesint MemAlloc - MemFree\n"); 

    mybuffer = (sample_buffer *) MemAlloc(sizeof(sample_buffer)); 

    if (mybuffer == NULL) 
    { 
    printf("ERROR ALLOCATING mybuffer\n"); 

    return EXIT_FAILURE; 
    } 

    bufferinfo = (buffer_info *) MemAlloc(sizeof(buffer_info)); 

    if (bufferinfo == NULL) 
    { 
    printf("ERROR ALLOCATING bufferinfo\n"); 

    MemFree(mybuffer); 

    return EXIT_FAILURE; 
    } 

    pCh = (char *)MemAlloc(sizeof(char)); 

    printf("finished malloc\n"); 

    // fill allocated memory with integers and read back some values 
    for(i = 0; i < BUFFERSIZE; ++i) 
    { 
    mybuffer->buffer[i] = i; 
    mybuffer->bools[i] = true; 
    bufferinfo->whichbuffer = (unsigned int)(i/100); 
    } 


    MemFree(bufferinfo); 
    MemFree(mybuffer); 

    if(pCh) 
    { 
    MemFree(pCh); 
    } 

    return EXIT_SUCCESS; 
} 
+0

MemAlloc에서 두 개의 malloc()이 필요하다고 생각하지 않습니다. 정렬을 위해 좋은 크기를 결정하는 매크로를 작성하거나 (모든 경우에 대해 충분할 것으로 생각합니다. 64 비트를 사용하십시오.) 메모리를 할당하기 전에 해당 양만큼 nSize를 추가하십시오. – Makis

+0

감사합니다. 나는 32 비트 플랫폼에있다. MemAlloc에서 단일 malloc을 사용하도록 구현을 업데이트했습니다. 나는 정렬에 요점을 이해하지 않습니다. 너무 많이 묻지 않는다면 문제가 될 수있는 곳에서 구현할 수 있습니다. 아마도, MemFree로 전달 된 포인터 또는 malloc에서 반환 된 포인터가 이미 정렬되지 않은 경우, 래퍼를 사용하지 않으면 이러한 정렬이 정렬되지 않기 때문에 수행 할 수있는 작업은 많지 않습니다. – dubnde

+1

다음은 문제에 대한 좋은 설명입니다 : http://www.goingware.com/tips/getting-started/alignment.html 내가뿐만 아니라 32 비트 크기의 정보를 가질 것,이 문제가 해결됩니다. 문제는 다음과 같을 수 있습니다. 위치 X부터 시작하여 메모리를 예약하고 처음 두 바이트는 크기 정보이므로 x + 2를 호출자에게 반환합니다. 그러나 정렬이 4 바이트이면 문제가 발생할 수 있습니다. size_t가 어떤 크기인지 확인하거나 이식성있는 코드를 원할 경우 일부 매크로를 정의해야합니다. – Makis

답변

12

래퍼에 몇 개의 추가 바이트를 할당하고 id (malloc() 및 free())를 결합하거나 원하는 크기 만 넣을 수 있습니다. 그냥 malloc에 ​​() 훨씬 더 많은 메모리, 당신은 많은 바이트 앞으로 돌아 포인터를 메모리 블록의 시작 부분에 정보를 저장하고 이동합니다.

펜스 포인터/지문 등에서도 쉽게 사용할 수 있습니다.

+3

반환하는 포인터의 정렬이 malloc에서 반환하는 포인터와 동일하거나 더 나은지 확인하십시오. – Eyal

+0

좋은 지적, Eyal.얼마나 많은 시간을 내가 불량 (일반적으로 구조체와 함께) 구운 상관없이 난 아직도 그것을 잊어 경향이 :) – Makis

+1

크기가 이미 거기에, 반환 된 포인터를 캐스팅 (int *) 및 ptr [-1]에서 값을 확인하십시오. 또는 ptr [-2]이다. 할당 된 크기는 정렬을 유지하기 위해 반올림 될 수 있으므로 123 바이트 버퍼에 대한 요청은 128 바이트를 반환 할 수 있으므로 그에 따라 확인하십시오. – TMN

1

직접 구현을 롤링하는 대신 언제든지 valgrind을 사용할 수 있습니다. 당신은 메모리의 양에 대한 상관 없어 경우에 당신은 할당 당신은 더 간단한 구현을 사용할 수 있습니다 (오류가있을 수 있도록 정말 빨리 이런 짓을하고 나는 그것이 가장 효율적인 구현 아니라고 실현 pAllocedStorage가 주어져야한다. 초기 크기 및 크기 조절 등 몇 가지 요인에 의해 증가하지만 당신은 아이디어를 얻을)

편집 :. 나는이 ARM에 대한 것을 놓친, 내 지식 Valgrind의가 ARM에서 사용할 수 없습니다 그래서이되지 않을 수도 있습니다 선택권.

static size_t indexAllocedStorage = 0; 
static size_t *pAllocedStorage = NULL; 
static unsigned int free_calls = 0; 
static unsigned long long int total_mem_alloced = 0; 

void * 
my_malloc(size_t size){ 
    size_t *temp; 
    void *p = malloc(size); 
    if(p == NULL){ 
    fprintf(stderr,"my_malloc malloc failed, %s", strerror(errno)); 
    exit(EXIT_FAILURE); 
    } 

    total_mem_alloced += size; 

    temp = (size_t *)realloc(pAllocedStorage, (indexAllocedStorage+1) * sizeof(size_t)); 
    if(temp == NULL){ 
     fprintf(stderr,"my_malloc realloc failed, %s", strerror(errno)); 
     exit(EXIT_FAILURE); 
    } 

    pAllocedStorage = temp; 
    pAllocedStorage[indexAllocedStorage++] = (size_t)p; 

    return p; 
} 

void 
my_free(void *p){ 
    size_t i; 
    int found = 0; 

    for(i = 0; i < indexAllocedStorage; i++){ 
    if(pAllocedStorage[i] == (size_t)p){ 
     pAllocedStorage[i] = (size_t)NULL; 
     found = 1; 
     break; 
     } 
    } 

    if(!found){ 
     printf("Free Called on unknown\n"); 
    } 

    free_calls++; 
    free(p); 
} 

void 
free_check(void) { 
    size_t i; 

    printf("checking freed memeory\n"); 
    for(i = 0; i < indexAllocedStorage; i++){ 
     if(pAllocedStorage[i] != (size_t)NULL){ 
      printf("Memory leak %X\n", (unsigned int)pAllocedStorage[i]); 
      free((void *)pAllocedStorage[i]); 
     } 
    } 

    free(pAllocedStorage); 
    pAllocedStorage = NULL; 
} 
0

나는 rmalloc을 사용할 것입니다. 메모리 사용량을 디버깅하는 간단한 라이브러리 (실제로는 두 개의 파일 임)이지만 통계도 지원합니다. 래퍼 함수는 이미 rmalloc을 사용하는 것이 매우 쉽습니다. strdup 등을 교체해야한다는 점도 명심하십시오.

0

또한 프로그램이 realloc(), calloc(), getcwd()를 가로 챌 필요가 있습니다 (일부 구현에서는 버퍼가 NULL 일 때 메모리를 할당 할 수 있음), strdup() 또는 지원되는 경우 비슷한 함수 컴파일러

+0

malloc() (와 realloc(), calloc(), alloca(), free())를 오버라이드하면 다른 모든 것을 free (말하자면)로 얻는다. – TMN

+0

내 프로그램은 MemAlloc과 MemFree 만 사용하므로 malloc과 free를 가로 채기 만하면됩니다. – dubnde

0

당신이 x86에서 실행중인 경우로 당신은 valgrind에서 바이너리를 실행할 수 있으며 mallocfree의 표준 구현을 사용하여, 당신을 위해 모든 정보를 수집합니다. 단순한.

0

나는이 페이지에서 언급 된 것과 동일한 기술을 시도해 왔으며 Google 검색에서이 책을 끝 냈습니다. 이 질문은 오래되었지만 기록을 추가하고 싶습니다. ...

1) 운영 체제는 실행중인 프로세스에서 사용중인 힙 메모리를 확인하는 도구를 제공하지 않습니까? 나는 당신이 ARM에 관해서 이야기하는 것을 본다. 그래서 이것이 사실일지도 모른다. 대부분의 모든 기능을 갖춘 OS에서는 cmd 라인 도구를 사용하여 힙 크기를 확인하는 것입니다.

2) libc에서 사용할 수있는 경우 대부분의 플랫폼에서 sbrk (0)은 데이터 세그먼트의 최종 주소를 알려줍니다. 가지고 있다면, 프로그램의 시작 부분에 그 주소를 저장하는 것만으로 (예 : startBrk = sbrk (0)), 할당 된 크기는 언제든지 sbrk (0) - startBrk가됩니다.

3) 공유 객체를 사용할 수 있고 libc에 동적으로 연결되어 있고 OS의 런타임 로더에 LD_PRELOAD 환경 변수가있는 경우 해당 객체를 정의하는 자신의 공유 객체를 만드는 것이 더 유용 할 수 있습니다. 실제 libc는 MemAlloc()이 아닌 malloc()을 사용하여 함수를 호출 한 다음 로더가 먼저 lib를로드하고 libc 함수를 "interpose"합니다. dlsym()과 RTLD_NEXT 플래그를 사용하여 실제 libc 함수의 주소를 얻을 수 있으므로 malloc/free 래퍼를 사용하기 위해 모든 코드를 다시 컴파일 할 필요없이 위에서 수행중인 작업을 수행 할 수 있습니다. 그런 다음 LD_PRELOAD = mymemdebug.so와 같은 환경 변수를 설정 한 다음 실행하면 프로그램 (또는 첫 번째 문장의 설명에 맞는 프로그램)을 시작할 때 런타임 결정이됩니다. (공유 객체 interposition을위한 구글. 그것은 훌륭한 기술이고 많은 디버거/프로파일 러에 의해 사용되는 기술입니다.)

+0

집안의 OS는 매우 간단합니다. 1) 아니오 (2) sbrk 사용할 수 없음 (3) 공유 오브젝트를 사용할 수 없음. – dubnde

관련 문제