malloc 와 free 함수 의 실현 코드 및 분석
K&R 제8 장 제5 절의 실현 을 연구 하기 전에 제5 장 제4 절의 alloc/afree 실현 을 먼저 살 펴 보 자.비록 이 코드 의 주요 목적 은 주소 연산 을 보 여 주 는 것 이지 만.
alloc
#define ALLOCSIZE 10000
static char allocbuf[ALLOCSIZE]; /*storage for alloc*/
static char *allocp = allocbuf; /*next free position*/
char *alloc(int n)
{
if(allocbuf+ALLOCSIZE - allocp >= n) {
allocp += n;
return alloc - n;
} else
return 0;
}
void afree(char *p)
{
if (p >= allocbuf && p<allocbuf + ALLOCSIZE)
allocp = p;
}
이런 간단 한 실현 의 단점:1.메모리 자원 을 대표 하 는 allocbuf 로 서 미리 분 배 된 것 이 므 로 낭비 가 있 을 수 있 습 니 다.
2.분배 와 방출 순 서 는 창고,즉'후진 선 출'과 유사 하 며 방출 시 순서대로 이상 을 초래 할 수 있다.
이 실현 은 비록 비교적 초라 하지만,여전히 하나의 사고방식 을 제공 했다.이 두 가지 단점 을 없 앨 수 있다 면 비교적 이상 적 인 malloc/freee 를 실현 할 수 있 을 것 이다.
주소 연산 에 만 의존 하여 포 지 셔 닝 을 하 는 것 은 분배 회수 유연성 을 제한 하 는 원인 으로 이미 사용 한 부분 과 사용 하지 않 은 부분 은 반드시 특정한 주 소 를 통 해 두 개의 인접 지역 으로 나 누 어야 한다 고 요구한다.이 두 구역 이 서로 교차 할 수 있 도록 심지어 분배 되 지 않 은 주소 공간 도 포함 되 어 있 기 때문에 포인터 로 같은 메모리 공간 을 연결 하여 링크 를 만들어 야 주소 가 연속 되 지 않 는 일련의 메모리 공간 을 처리 할 수 있다.그런데 왜 빈 공간 만 연결 하고 사용 중인 공간 은 연결 하지 않 습 니까?이렇게 묻 는 것 은 그림 에서 두 사람 을 비교 할 때의 직관 에서 비롯 되 어 생각 을 하지 않 았 을 수도 있다.이것 은 매우 간단 하 다.왜냐하면 필요 하지 않 기 때문이다.전자 가 서로 연결 하 는 것 은 메모리 가 분 배 될 때 모든 빈 공간 을 옮 겨 다 니 고 free()를 사용 하여 사용 한 공간 을 회수 할 때 다시 삽입 할 수 있 도록 하 는 것 입 니 다.사용 중인 공간 에 대해 우 리 는 공간 을 분배 할 때 이미 그들의 주 소 를 알 고 있 기 때문에 회수 할 때 free()에 게 직접 알려 줄 수 있 고 malloc()처럼 옮 겨 다 니 지 않 아 도 된다.
링크 가 언급 된 이상 데이터 구조 에 대해 조금 아 는 사람 은 바로 다음 struct 를 써 서 메모리 영역 을 대표 할 수 있 습 니 다.그 중에서 다음 메모리 영역 을 가리 키 는 지침 이 포함 되 어 있 습 니 다.그러나 이 struct 의 다른 구성원 들 은 어떻게 써 야 합 니까?분 배 될 메모리 영역 으로서 크기 가 정 해 지지 않 습 니 다.이 를 struct 로 설명 하 는 구성원 변 수 는 분명 적절 하지 않 습 니 다.다른 지역 을 가리 키 는 지침 이 라 고 밝 히 면 위의 직관 적 인 표현 과 맞지 않 는 것 같다.물론 이렇게 하 는 것 도 실현 할 수 있다.이것 은 위의 그림 과 같은 두 가지 사이 에 있 고 관리 구조 와 실제 분 배 된 공간 을 분리 시 키 는 것 처럼 보인다.글 끝 에 나 는 이런 실현 방법 을 전문 적 으로 토론 할 것 이다)그래서 여 기 는 아직도 제어 구조 와 여가 공간 을 분리 시 키 지만 메모리 주소 에서 서로 인접 하여 다음 그림 의 형식 을 형성 하 는 것 이 바로 이런 특징 이다.우 리 는 제어 구조 지침 에 대한 지침 연산 을 이용 하여 대응 하 는 메모리 영역 을 찾 을 수 있다.
대응 하여 제어 정 보 를 Header:
typedef long Align;/*for alignment to long boundary*/
union header {
struct {
union header *ptr; /*next block if on free list*/
unsigned size; /*size of this block*/
} s;
Align x;
};
typedef union header Header;
으로 정의 합 니 다.struct 대신 유 니 온 을 사용 하 는 이 유 는 주소 정렬 을 위 한 것 입 니 다.여 기 는 롱 정렬 입 니 다.유 니 온 의 x 는 영원히 사용 되 지 않 습 니 다.
이렇게 해서 malloc 의 주요 업 무 는 바로 이러한 Header 와 그 후의 메모리 블록 에 대한 관리 이다.
malloc()
static Header base;
static Header *freep = NULL;
void *malloc(unsigned nbytes)
{
Header *p, *prevp;
unsigned nunits;
nunits = (nbytes+sizeof(Header)-1)/sizeof(Header) + 1;
if((prevp = freep) == NULL) { /* no free list */
base.s.ptr = freep = prevp = &base;
base.s.size = 0;
}
for(p = prevp->s.ptr; ;prevp = p, p= p->s.ptr) {
if(p->s.size >= nunits) { /* big enough */
if (p->s.size == nunits) /* exactly */
prevp->s.ptr = p->s.ptr;
else {
p->s.size -= nunits;
p += p->s.size;
p->s.size = nunits;
}
freep = prevp;
return (void*)(p+1);
}
if (p== freep) /* wrapped around free list */
if ((p = morecore(nunits)) == NULL)
return NULL; /* none left */
}
}
실제 분 배 된 공간 은 Header 크기 의 정수 배 이 고 Header 크기 의 공간 을 하나 더 만들어 Header 를 배치 하 는 데 사용 합 니 다.그러나 직관 적 으로 보면 이것 은 nunits=(nbytes+sizeof(Header)-1)/sizeof(Header)+1 이 아 닙 니까?(nbytes+sizeof(Header)/sizeof(Header)+1 을 사용 하면 딱 좋 지 않 을까요?사실은 그렇지 않 습 니 다.후 자 를 사용 하면 nbytes+sizeof(Header)%sizeof(Header)=0 시 에 Header 크기 의 공간 을 하나 더 분 배 했 기 때문에 작은 괄호 에서 1 을 빼 야 요구 에 부합 할 수 있 습 니 다.malloc()가 처음 호출 되 었 을 때 퇴화 링크 base 를 만 들 었 습 니 다.크기 가 0 인 공간 만 있 고 자신 을 가리 키 고 있 습 니 다.freep 는 빈 링크 의 특정한 요 소 를 표시 하 는 데 사용 되 며 찾 을 때마다 변화 가 발생 할 수 있 습 니 다.중간 검색 과 배분 과정 은 기본 적 인 링크 작업 으로 남 은 링크 에 적당 한 크기 의 남 은 공간 이 존재 하지 않 을 때 morecore()를 호출 하여 더 많은 메모리 공간 을 얻 습 니 다.마지막 반환 값 은 빈 공간의 첫 번 째 주소,즉 Header 다음 주소 입 니 다.이 인 터 페 이 스 는 라 이브 러 리 함수 와 일치 합 니 다.
morecore()
#define NALLOC 1024 /* minimum #units to request */
static Header *morecore(unsigned nu)
{
char *cp;
Header *up;
if(nu < NALLOC)
nu = NALLOC;
cp = sbrk(nu * sizeof(Header));
if(cp == (char *)-1) /* no space at all*/
return NULL;
up = (Header *)cp;
up->s.size = nu;
free((void *)(up+1));
return freep;
}
morecore()는 시스템 에서 더 많은 사용 가능 한 공간 을 신청 하고 가입 합 니 다.sbrk()를 호출 했 기 때문에 시스템 비용 이 많이 들 었 습 니 다.morecore()자체 의 호출 횟수 를 피하 기 위해 NALLOC 를 설 정 했 습 니 다.매번 신청 한 공간 이 NALLOC 보다 작 으 면 NALLOC 크기 의 공간 을 신청 하여 후속 malloc()가 매번 morecore()를 호출 하지 않 아 도 됩 니 다.sbrk()에 대해 서 는 뒤에서 소개 해 드 리 겠 습 니 다.여기 놀 라 운 점 이 있 습 니 다.malloc()는 morecore()를 호출 했 고 morecore()는 free()를 호출 했 습 니 다!이곳 을 처음 봤 을 때 신기 할 수도 있 습 니 다.관성 적 인 사고 에 따 르 면 malloc()와 free()는 서로 분 리 된 것 같 아서 각자 맡 은 일 을 해 야 할 것 같 습 니 다.그러나 다시 한 번 생각해 보 세 요.free()는 빈 링크 를 확장 하 는 것 입 니 다.malloc()는 빈 링크 가 부족 할 때 시스템 에서 더 많은 메모리 공간 으로 신청 한 후에 도 빈 링크 의 일부분 으로 전환 시 킨 다음 에 이용 해 야 합 니 다.이렇게 해서 malloc()가 free()를 호출 하여 뒤의 일 을 완성 하 는 것 도 순리 적 이다.이 사상 에 따 르 면 뒤 에는 free()의 실현 이다.그 전에 morecore()자체 의 세부 사항 이 몇 개 있 습 니 다.
1.시스템 에 분배 할 공간 이 없 으 면 sbrk()는-1 로 되 돌아 갑 니 다.cp 는 char*형식 입 니 다.어떤 기계 에 서 는 char 기호 가 없습니다.강제 형식 변환 이 필요 합 니 다.
2.morecore()호출 된 반환 값 이 이상해 보 입 니 다.걱정 하지 마 세 요.freep 는 free()에서 수정 할 것 입 니 다.이 반환 값 을 사용 하 는 것 도 malloc()에서 의 판단,p=freep 의 재 할당 문 구 를 치밀 하 게 하기 위해 서 입 니 다.
free()
void free(void *ap)
{
Header *bp,*p;
bp = (Header *)ap -1; /* point to block header */
for(p=freep;!(bp>p && bp< p->s.ptr);p=p->s.ptr)
if(p>=p->s.ptr && (bp>p || bp<p->s.ptr))
break; /* freed block at start or end of arena*/
if (bp+bp->s.size==p->s.ptr) { /* join to upper nbr */
bp->s.size += p->s.ptr->s.size;
bp->s.ptr = p->s.ptr->s.ptr;
} else
bp->s.ptr = p->s.ptr;
if (p+p->s.size == bp) { /* join to lower nbr */
p->s.size += bp->s.size;
p->s.ptr = bp->s.ptr;
} else
p->s.ptr = bp;
freep = p;
}
free()먼저 풀 어야 할 ap 에 대응 하 는 bp 와 남 은 링크 의 상대 적 인 위 치 를 찾 습 니 다.가장 가 까 운 이전 과 다음 남 은 공간 을 찾 거나 전체 남 은 공간의 앞 이나 뒤에 있 을 때 남 은 링크 의 첫 번 째 요 소 를 찾 습 니 다.malloc()의 배분 방식 과 free()의 회수 시 합병 방식(다음 글 에서 곧 언급 할 것)으로 인해 전체 빈 공간의 링크 가 항상 낮은 주소 에서 하나씩 올 라 가 고 최고 주소 의 빈 공간 에서 낮은 주소 의 첫 번 째 빈 공간 을 가리 키 도록 할 수 있 습 니 다.포 지 셔 닝 후 방출 할 공간 과 인근 공간의 인접 성에 따라 통합 하 는 것,즉 해당 공간의 Header 를 수정 하 는 것 이다.두 if 를 병렬 하면 bp 가 높 은 주소 와 낮은 주소 의 빈 공간 과 결합 하거나 둘 중 하 나 를 합병 하거나 합병 하지 않 을 수 있 습 니 다.
이 세 부분 코드 를 완성 한 후(같은 원본 파일 에 넣 으 면 sbrk()는\#include
처음으로 소스 코드 를 살 펴 보면 Header 의 구조 와 정렬 충전,공간의 정리,링크 의 조작 과 초기 화(경계 상황),malloc()대 free()의 호출,malloc()와 free()가 몰래 보장 하 는 링크 주소 의 질서 등 이 생각 하지 못 했 을 수도 있 습 니 다.또한 앞에서 언급 한 두 가지 문 제 를 동봉 하고 보충 문제 에 대한 간단 한 사고 도 있다.
1.Header 는 남 은 공간 과 분리 되 고 Header 에는 남 은 공간 을 가리 키 는 지침 이 포함 되 어 있 습 니 다.
이렇게 하면 반드시 안 되 는 것 은 아니 며,상응하는 알고리즘 은 바 꿔 야 한다.또한,Header 와 남 은 공간 이 더 이상 인접 하지 않 기 때문에 sbrk()가 얻 은 공간 도 Header 의 부분 을 포함해 야 하 며 메모리 의 분 포 는 더욱 번 거 로 울 수 있 습 니 다.물론 이것 은 좋 은 점 을 가 져 올 수 있다.즉,다른 데이터 구조 로 링크 를 관리 하 는 것 이다.예 를 들 어 크기 에 따라 hash 를 하면 더욱 빨리 찾 을 수 있다.
2.sbrk()에 대하 여
sbrk()도 라 이브 러 리 함수 입 니 다.스 택 으로 쌓 이 는 방향 을 증가 시 킬 수 있 습 니 다.구체 적 으로 는 brk(),sbrk()용법 에 대한 상세 한 설명 을 참고 할 수 있 습 니 다.
3.개선 할 수 있 는 방법
남 은 공간 을 찾 는 것 은 선형 이 고 검색 과정 은 메모리 배분 에서 순환 의 첫 번 째 적응 알고리즘 으로 볼 수 있 으 며 어떤 경우 에는 느 릴 수 있 습 니 다.만약 에 hash 표 와 같은 데이터 구 조 를 다시 만 들 면 서로 다른 크기 의 공간 을 색인 하면 그 자 체 를 빨리 찾 을 수 있 고 알고리즘 을 실현 할 수 있 습 니 다.예 를 들 어 가장 좋 은 일치 등 입 니 다.그러나 검색 이 빨 라 지 는 대 가 는 이 색인 을 수정 하 는 데 추가 시간 이 걸 리 므 로 저울질 해 야 한 다 는 것 이다.
morecore()의 최소 분배 공간 은 매크로 정의 로 실제 사용 에서 매개 변수 로 전달 할 수 있 으 며 필요 에 따라 최소 분배 하한 선 을 설정 할 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
c 언어 간단한 파일 r/w 조작 방법데이터의 입력과 출력은 거의 모든 C 언어 프로그램과 수반된다. 입력이란 원본에서 데이터를 얻는 것이다. 출력은 단말기에 데이터를 쓰는 것으로 이해할 수 있다.이곳의 원본은 키보드, 마우스, 하드디스크, 시디, 스캐...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.