malloc () 및 free ()는 어떻게 작동합니까?
방법 malloc
과 free
작업 을 알고 싶습니다 .
int main() {
unsigned char *p = (unsigned char*)malloc(4*sizeof(unsigned char));
memset(p,0,4);
strcpy((char*)p,"abcdabcd"); // **deliberately storing 8bytes**
cout << p;
free(p); // Obvious Crash, but I need how it works and why crash.
cout << p;
return 0;
}
가능한 경우 대답이 메모리 수준에서 깊이 있으면 정말 감사 할 것입니다.
확인 malloc에 대한 답변이 이미 게시되었습니다.
더 흥미로운 부분은 자유 가 어떻게 작동 하는가입니다 (이 방향에서 malloc도 더 잘 이해할 수 있습니다).
많은 malloc / free 구현에서 free는 일반적으로 메모리를 운영 체제로 리턴하지 않습니다 (또는 드문 경우에만). 그 이유는 힙에 공백이 생겨서 2GB 또는 4GB의 가상 메모리를 공백으로 마무리하기 때문입니다. 가상 메모리가 완료 되 자마자 큰 어려움에 처하게되므로 피해야합니다. 다른 이유는 OS가 특정 크기와 정렬을 가진 메모리 청크 만 처리 할 수 있기 때문입니다. 구체적으로 : 일반적으로 OS는 가상 메모리 관리자가 처리 할 수있는 블록 만 처리 할 수 있습니다 (대개 512 바이트의 배수 (예 : 4KB)).
따라서 OS에 40 바이트를 반환하면 작동하지 않습니다. 그래서 무료는 무엇을 하는가?
Free는 메모리 블록을 자체 빈 블록 목록에 넣습니다. 일반적으로 주소 공간에서 인접한 블록을 함께 병합하려고 시도합니다. 사용 가능한 차단 목록은 시작 부분에 관리 데이터가있는 순환 메모리 청크 목록입니다. 이것이 표준 malloc / free로 매우 작은 메모리 요소를 관리하는 것이 효율적이지 않은 이유이기도합니다. 모든 메모리 청크에는 추가 데이터가 필요하며 크기가 작을수록 조각화가 더 많이 발생합니다.
자유 목록은 또한 malloc이 새로운 메모리 덩어리가 필요할 때 처음 보는 장소입니다. OS에서 새 메모리를 호출하기 전에 스캔됩니다. 필요한 메모리보다 큰 청크가 발견되면 두 부분으로 나뉩니다. 하나는 발신자에게 반환되고 다른 하나는 다시 무료 목록으로 돌아갑니다.
이 표준 동작에 대한 여러 가지 최적화가 있습니다 (예 : 작은 메모리 청크). 그러나 malloc과 free는 매우 보편적이어야하기 때문에 대안을 사용할 수없는 경우 표준 동작은 항상 폴백입니다. 또한 프리리스트를 처리 할 때 최적화가 있습니다 (예 : 크기별로 정렬 된 목록에 청크 저장). 그러나 모든 최적화에는 자체 제한이 있습니다.
왜 코드가 충돌합니까?
그 이유는 4 개의 문자로 된 영역에 9 개의 문자 (후미 널 바이트를 잊지 마십시오)를 쓰면 데이터 청크 뒤에있는 다른 메모리 청크에 저장된 관리 데이터를 덮어 쓰게되기 때문입니다 ( 이 데이터는 대부분 메모리 청크의 "앞에"저장되므로). 그러면 free가 청크를 free list에 넣으려고 할 때이 관리 데이터를 건 드리면 덮어 쓴 포인터 위로 넘어 질 수 있습니다. 시스템이 중단됩니다.
이것은 다소 우아한 행동입니다. 또한 어딘가에 런 어웨이 포인터가 memory-free-list의 데이터를 덮어 쓰고 시스템이 즉시 충돌하지는 않지만 나중에 일부 서브 루틴이 발생하는 상황을 보았습니다. 중간 정도의 복잡한 시스템에서도 이러한 문제는 실제로 디버깅하기가 매우 어려울 수 있습니다! 내가 관여했던 한 경우, 메모리 덤프에 표시된 것과 완전히 다른 위치에 있었기 때문에 충돌의 원인을 찾는 데 며칠이 걸렸습니다. 시한 폭탄과 같습니다. 다음 "무료"또는 "멀록"이 충돌하지만 그 이유를 모릅니다.
이것들은 최악의 C / C ++ 문제이며 포인터가 그렇게 문제가 될 수있는 한 가지 이유입니다.
프로세스에는 주소 x에서 주소 y까지 힙이라는 메모리 영역이 있습니다. 모든 malloc의 데이터는이 영역에 있습니다. malloc ()은 힙에서 사용 가능한 공간의 모든 청크에 대한 일부 데이터 구조를 유지합니다. malloc을 호출하면 목록을 통해 충분히 큰 청크를 찾고 포인터를 반환하고 더 이상 비어 있지 않은 사실과 그것이 얼마나 큰지 기록합니다. 같은 포인터로 free ()를 호출하면 free ()는 해당 청크의 크기를 찾아서 free chunks () 목록에 다시 추가합니다. malloc ()을 호출하고 힙에서 충분히 큰 청크를 찾을 수 없으면 brk () syscall을 사용하여 힙을 증가시킵니다. 즉, 주소 y를 늘리고 이전 y와 새 y 사이의 모든 주소를 유효한 메모리 여야합니다. brk ()는 syscall이어야합니다.
malloc ()은 시스템 / 컴파일러에 따라 다르므로 구체적인 대답을하기가 어렵습니다. 그러나 기본적으로 할당 된 메모리를 추적하고 사용 방법에 따라 무료 통화가 실패하거나 성공 할 수 있습니다.
malloc() and free() don't work the same way on every O/S.
malloc / free의 한 구현은 다음을 수행합니다.
- sbrk () (Unix 호출)를 통해 OS에서 메모리 블록을 확보하십시오.
- 크기, 권한, 다음 및 이전 블록의 위치와 같은 정보를 사용하여 해당 메모리 블록 주위에 머리글과 바닥 글을 만듭니다.
- malloc에 대한 호출이 들어 오면 적절한 크기의 블록을 가리키는 목록이 참조됩니다.
- 그런 다음이 블록이 반환되고 이에 따라 머리글과 바닥 글이 업데이트됩니다.
메모리 보호에는 페이지 세분성이 있으며 커널 상호 작용이 필요합니다.
예제 코드는 본질적으로 예제 프로그램이 트랩되지 않는 이유를 묻습니다. 그리고 메모리 보호는 커널 기능이며 전체 페이지에만 적용되는 반면 메모리 할당자는 라이브러리 기능이며 강제로 .. 종종 페이지보다 훨씬 작은 크기의 블록.
메모리는 프로그램에서 페이지 단위로만 제거 할 수 있으며 심지어 관찰되지 않을 수도 있습니다.
calloc (3)과 malloc (3)은 필요한 경우 커널과 상호 작용하여 메모리를 얻습니다. 그러나 대부분의 free (3) 구현은 메모리를 커널 1로 반환하지 않으며 , 해제 된 블록을 재사용하기 위해 calloc () 및 malloc ()이 나중에 참조 할 빈 목록에 추가합니다.
free ()가 시스템에 메모리를 반환하려고하더라도 커널이 실제로 영역을 보호하도록하려면 적어도 하나의 연속 메모리 페이지가 필요하므로 작은 블록을 해제하면 보호 변경이 발생합니다. 페이지 의 마지막 작은 블록
그래서 당신의 블록은 무료 목록에 있습니다. 여전히 할당 된 것처럼 거의 항상 메모리와 주변 메모리에 액세스 할 수 있습니다. C는 머신 코드로 직접 컴파일되며 특별한 디버깅 배열이 없으면로드 및 저장에 대한 온 전성 검사가 없습니다. 이제 사용 가능한 블록에 액세스하려고하면 라이브러리 구현 자에 부당한 요구를하지 않기 위해 표준에 의해 동작이 정의되지 않습니다. 할당 된 블록 외부에서 해제 된 메모리 나 메모리에 액세스하려고하면 잘못 될 수있는 여러 가지가 있습니다.
- 때때로 할당자는 별도의 메모리 블록을 유지 관리하고 때로는 블록 바로 앞이나 뒤에 할당 한 헤더를 사용하지만 ( "바닥 글"이라고 생각합니다.) 사용 가능한 목록을 유지하기 위해 블록 내에서 메모리를 사용하려고 할 수도 있습니다. 서로 연결되어 있습니다. 그렇다면 블록을 읽을 수는 있지만 내용이 변경 될 수 있으며 블록에 쓰면 할당자가 잘못 작동하거나 충돌 할 수 있습니다.
- 당연히 블록은 나중에 할당 될 수 있으며 코드 또는 라이브러리 루틴으로 덮어 쓰거나 calloc ()로 0을 덮어 쓸 수 있습니다.
- 블록이 재 할당되면 크기도 변경 될 수 있으며,이 경우 더 많은 링크 또는 초기화가 다양한 위치에 작성됩니다.
- 분명히 당신은 프로그램의 커널 알려진 세그먼트 중 하나의 경계를 넘어 범위를 벗어난 범위를 참조 할 수 있으며,이 경우 트랩 할 것입니다.
작동 이론
따라서 예제에서 전반적인 이론으로 거꾸로 작업하면 malloc (3)은 필요할 때 커널에서 메모리를 가져옵니다 (일반적으로 페이지 단위). 이 페이지들은 프로그램에 따라 분할되거나 통합됩니다. Malloc과 무료로 협력하여 디렉토리를 유지합니다. 그들은 가능한 큰 블록을 제공 할 수 있도록 인접한 자유 블록을 합칩니다. 디렉토리는 해제 된 블록에서 메모리를 사용하여 링크 된 목록을 형성하는 것을 포함하거나 포함하지 않을 수 있습니다. (대안은 좀 더 공유 메모리와 페이징 친화적이며 디렉토리에 특별히 메모리를 할당하는 것과 관련이 있습니다.) Malloc과 free는 특별하고 선택적인 디버깅 코드가 프로그램.
1. free () 구현이 시스템에 메모리를 반환하려고 시도하는 경우가 거의 없다는 사실은 구현자가 느슨해 졌기 때문일 필요는 없습니다. 커널과의 상호 작용은 단순히 라이브러리 코드를 실행하는 것보다 훨씬 느리며 이점은 적습니다. 대부분의 프로그램은 정상 상태이거나 메모리 사용량이 증가하므로 반환 가능한 메모리를 찾는 힙을 분석하는 데 소요되는 시간이 완전히 낭비됩니다. 다른 이유는 내부 조각화로 페이지 정렬 블록이 존재하지 않을 가능성이 있으며, 블록을 반환하면 블록이 양쪽으로 조각화 될 가능성이 있습니다. 마지막으로 많은 양의 메모리를 반환하는 소수의 프로그램은 malloc ()을 무시하고 페이지를 할당하고 해제하기 만합니다.
이론적으로 malloc은이 응용 프로그램의 운영 체제에서 메모리를 가져옵니다. 그러나 4 바이트 만 원할 수 있고 OS는 페이지 (4 k)에서 작동해야하기 때문에 malloc은 그 이상을 수행합니다. 페이지를 가져 와서 자체 정보를 저장하므로 해당 페이지에서 할당하고 해제 한 내용을 추적 할 수 있습니다.
예를 들어, malloc은 4 바이트를 할당 할 때 4 바이트에 대한 포인터를 제공합니다. malloc은 4 바이트 이전 8-12 바이트의 메모리 를 사용하여 할당 한 모든 메모리 체인을 만드는 것을 알지 못할 수도 있습니다 . free를 호출하면 포인터를 가져 와서 데이터가있는 위치로 백업하고 작동합니다.
메모리를 비우면 malloc은 해당 메모리 블록을 체인에서 꺼내고 해당 메모리를 운영 체제에 반환하거나 반환하지 않을 수 있습니다. 그렇다면 OS가 해당 위치에 액세스 할 수있는 권한을 빼앗기 때문에 해당 메모리에 액세스하는 것보다 실패 할 수 있습니다. malloc이 메모리를 유지하면 (해당 페이지에 다른 것들이 할당되어 있거나 일부 최적화되어 있기 때문에) 액세스가 작동합니다. 여전히 잘못되었지만 작동 할 수 있습니다.
면책 조항 : 내가 설명한 것은 malloc의 일반적인 구현이지만 결코 유일하게 가능한 것은 아닙니다.
strcpy 행은 NUL 종료 자로 인해 8이 아닌 9 바이트를 저장하려고합니다. 정의되지 않은 동작을 호출합니다.
무료 통화는 중단되거나 중단되지 않을 수 있습니다. 할당의 4 바이트 "후"메모리는 C 또는 C ++ 구현에 의해 다른 용도로 사용될 수 있습니다. 그것이 다른 것에 사용된다면, 그 모든 것에 낙서를하면 "다른 것"이 잘못 될 수 있지만, 다른 것에 사용되지 않으면, 당신은 그것을 피할 수 있습니다. "그것으로 도망 치다"는 소리는 좋지만 실제로는 나쁘다. 왜냐하면 그것은 코드가 정상적으로 실행되는 것처럼 보일 것이기 때문이다.
디버깅 스타일 메모리 할당자를 사용하면 특별한 가드 값이 작성되었으며 해당 값과 패닉이없는 경우이를 무료로 확인할 수 있습니다.
그렇지 않으면 다음 5 바이트에 아직 할당되지 않은 다른 메모리 블록에 속하는 링크 노드의 일부가 포함되어있을 수 있습니다. 블록을 해제하면 사용 가능한 블록 목록에 블록을 추가하는 것이 좋을 수 있으며 목록 노드에서 낙서했기 때문에 해당 작업은 잘못된 값을 가진 포인터를 역 참조하여 충돌을 일으킬 수 있습니다.
그것은 모두 메모리 할당 자에 달려 있습니다-다른 구현은 다른 메커니즘을 사용합니다.
malloc () 및 free () 작동 방식은 사용 된 런타임 라이브러리에 따라 다릅니다. 일반적으로 malloc ()은 운영 체제에서 힙 (메모리 블록)을 할당합니다. malloc ()에 대한 각 요청은이 메모리의 작은 청크를 할당하여 호출자에게 포인터를 리턴합니다. 메모리 할당 루틴은 힙에서 사용 된 여유 메모리를 추적 할 수 있도록 할당 된 메모리 블록에 대한 추가 정보를 저장해야합니다. 이 정보는 종종 malloc ()에 의해 리턴 된 포인터 직전에 몇 바이트에 저장되며 링크 된 메모리 블록 목록 일 수 있습니다.
malloc ()에 의해 할당 된 메모리 블록을 지나서 쓰면 다음 블록의 예약 유지 정보 중 일부를 파괴 할 가능성이 높습니다.
너무 많은 문자를 버퍼에 복사 할 때 프로그램이 중단 될 수도 있습니다. 여분의 문자가 힙 외부에있는 경우 존재하지 않는 메모리에 쓰려고 할 때 액세스 위반이 발생할 수 있습니다.
이것은 malloc과 관련이 없으며 무료입니다. 문자열을 복사 한 후 프로그램에 정의되지 않은 동작이 나타납니다. 해당 시점 또는 이후에 충돌이 발생할 수 있습니다. malloc을 사용하지 않고 free를 사용하지 않고 스택에 또는 정적으로 char 배열을 할당 한 경우에도 마찬가지입니다.
malloc 및 free는 구현에 따라 다릅니다. 일반적인 구현은 사용 가능한 메모리를 "사용 가능한 목록"(사용 가능한 메모리 블록의 링크 된 목록)으로 분할하는 것입니다. 많은 구현에서 인위적으로 작은 객체와 큰 객체로 나눕니다. 사용 가능한 블록은 메모리 블록의 크기와 다음 블록의 위치 등에 대한 정보로 시작합니다.
당신이 malloc하면, 블록은 무료 목록에서 가져옵니다. 해제하면 블록이 해제 목록으로 돌아갑니다. 포인터 끝을 덮어 쓸 때 사용 가능한 목록의 블록 헤더에 쓸 수 있습니다. 메모리를 비우면 free ()는 다음 블록을 보려고 시도하고 아마도 버스 오류를 유발하는 포인터에 도달하게됩니다.
그것은 메모리 할당 기 구현과 OS에 달려 있습니다.
예를 들어, 윈도우에서 프로세스는 페이지 이상의 RAM을 요청할 수 있습니다. 그런 다음 OS는 해당 페이지를 프로세스에 할당합니다. 그러나 이것은 응용 프로그램에 할당 된 메모리가 아닙니다. CRT 메모리 할당자는 메모리를 연속 "사용 가능한"블록으로 표시합니다. 그런 다음 CRT 메모리 할당자는 사용 가능한 블록 목록을 실행하여 사용할 수있는 가장 작은 블록을 찾습니다. 그런 다음 필요한만큼의 블록을 가져 와서 "할당 된"목록에 추가합니다. 실제 메모리 할당의 헤드에 첨부되는 것은 헤더입니다. 이 헤더에는 다양한 정보가 포함됩니다 (예를 들어, 링크 된 목록을 구성하기 위해 다음 및 이전에 할당 된 블록을 포함 할 수 있습니다. 대부분의 경우 할당 크기를 포함합니다).
그런 다음 Free는 헤더를 제거하고 사용 가능한 메모리 목록에 다시 추가합니다. 주변 여유 블록과 함께 더 큰 블록을 형성하면 더 큰 블록을 제공하기 위해 함께 추가됩니다. 이제 전체 페이지가 해제되면 할당자는 해당 페이지를 OS로 반환합니다.
간단한 문제는 아닙니다. OS 할당 자 부분은 완전히 제어 할 수 없습니다. Doug Lea의 Malloc (DLMalloc)과 같은 내용을 읽고 상당히 빠른 할당자가 어떻게 작동하는지 이해하는 것이 좋습니다.
편집 : 할당보다 큰 값을 쓰면 다음 메모리 헤더를 덮어 썼기 때문에 충돌이 발생합니다. 이 방법을 사용하면 해제 할 때 정확히 무엇이 사용되는지와 다음 블록으로 병합하는 방법에 대해 매우 혼란스러워집니다. 이것은 항상 무료로 즉시 충돌을 일으킬 수 있습니다. 나중에 충돌이 발생할 수 있습니다. 일반적으로 메모리 덮어 쓰기를 피하십시오!
귀하가 소유하지 않은 메모리를 사용했기 때문에 프로그램이 충돌합니다. 다른 사람이 사용하거나 사용하지 않을 수 있습니다. 운이 좋으면 충돌하지 않으면 문제가 오랫동안 숨겨져 서 나중에 다시 물릴 수 있습니다.
malloc / free 구현이 진행되는 한, 모든 책이 주제에 집중되어 있습니다. 기본적으로 할당자는 OS에서 더 큰 메모리 덩어리를 가져 와서 관리합니다. 할당자가 해결해야하는 몇 가지 문제는 다음과 같습니다.
- 새로운 기억을 얻는 방법
- 그것을 저장하는 방법-(목록 또는 다른 구조, 크기가 다른 메모리 청크에 대한 여러 목록 등)
- 사용자가 현재 사용 가능한 것보다 더 많은 메모리를 요청하는 경우 수행 할 작업
- 사용자가 메모리를 비울 때 수행 할 작업
- 디버그 할당자는 요청한 더 큰 청크를 제공하고 바이트 패턴을 채울 수 있습니다. 메모리를 비울 때 할당자는 블록 외부에 기록되었는지 확인할 수 있습니다 (어쩌면 귀하의 경우에 발생합니다) ...
실제 동작이 다른 컴파일러 / 런타임마다 다르기 때문에 말하기가 어렵습니다. 디버그 / 릴리스 빌드조차도 동작이 다릅니다. VS2005의 디버그 빌드는 할당 사이에 마커를 삽입하여 메모리 손상을 감지하므로 충돌 대신 free ()로 선언됩니다.
그것은 단순히 주변에 프로그램 브레이크 포인터를 이동하는 것을 깨닫게하는 것도 중요 brk
하고 sbrk
실제로하지 않습니다 할당 메모리를, 그냥 주소 공간을 설정합니다. 예를 들어 Linux에서 주소 범위에 액세스하면 실제 물리적 페이지가 메모리를 "백업"하여 페이지 오류가 발생하고 결국 커널이 페이지 할당자를 호출하여 백업 페이지를 가져옵니다.
참고 URL : https://stackoverflow.com/questions/1119134/how-do-malloc-and-free-work
'Programing' 카테고리의 다른 글
밑이 2 진 문자열을 int로 변환 (0) | 2020.03.31 |
---|---|
기능적 요구 사항과 비 기능적 요구 사항의 차이점은 무엇입니까? (0) | 2020.03.31 |
카메라에서 이미지 캡처 및 활동 표시 (0) | 2020.03.31 |
텍스트 영역의 줄 바꿈 (0) | 2020.03.31 |
안드로이드에서 토스트의 위치를 바꾸는 방법? (0) | 2020.03.31 |