C의`free`가 해제 할 바이트 수를 사용하지 않는 이유는 무엇입니까?


84

그냥 확실하게합니다 : 알아요 않습니다 mallocfree일반적으로 OS에서 메모리 청크를 할당하고 응용 프로그램에 메모리의 작은 제비를 소포 자체 관리를 수행하고 할당 된 바이트의 수를 추적 C 라이브러리에서 구현된다 . 이 질문은 어떻게 free does free to free 가 아닙니다 .

오히려 free애초에 이런 식으로 만들어진 이유를 알고 싶습니다 . 저수준 언어이기 때문에 C 프로그래머에게 할당 된 메모리뿐만 아니라 얼마나 많은지를 추적하도록 요청하는 것이 완벽하게 합리적이라고 생각합니다 (사실 저는 일반적으로 바이트 수를 추적하게됩니다. 어쨌든 malloced). 또한 명시 적으로 바이트 free수를 제공하여 일부 성능 최적화를 허용 할 수 있습니다. 예를 들어 서로 다른 할당 크기에 대해 별도의 풀이있는 할당자는 입력 인수를보고 해제 할 풀을 결정할 수 있습니다. 전체적으로 공간 오버 헤드가 적습니다.

그래서, 짧은에, 왜했다 malloc그리고 free그들이 내부적으로 할당 된 바이트 수를 추적하는 데 필요한하고 있다는 등의 생성? 그것은 단지 역사적인 사고입니까?

약간의 수정 : 몇몇 사람들이 "할당 한 금액과 다른 금액을 확보하면 어떨까요"와 같은 포인트를 제공했습니다. 내 상상 한 API는 할당 된 바이트 수를 정확히 해제하기 위해 간단하게 필요할 수 있습니다. 어느 정도 해방하는 것은 단순히 UB 또는 구현 정의 일 수 있습니다. 그래도 다른 가능성에 대한 논의를 중단하고 싶지는 않습니다.


18
할당 자체를 추적하는 것은 이미 고통스럽고 크기를 추가로 추적해야하는 경우 코드를 더 복잡하게 만들기 때문입니다.
Jens Gustedt 2014-06-13

11
몇 가지 이유를 생각할 수 있습니다. 사용자가 필요하지 않은데 왜 그렇게하게 만들까요? 사용자가 엉망으로 만들면 어떻게 되나요? 어쨌든 중복되는 질문입니다. 그들이 다른 선택을했다면, 당신은 여전히 ​​그 이유를 묻고있을 것입니다.
BoBTFish 2014-06-13

15
@BoBTFish :이은 C 우리가하지 파이썬 또는 C ++ 얘기. 사용자는 이미 $ h! 1 톤을해야 할 필요가 없습니다. 그것은 이유가 아닙니다.
user541686

4
K & R도 이것에 대해 할 말이 없습니다. 우리는 우리가 좋아하는 모든 것을 추측 할 수 있지만 원래 이유는 역사에서 잃어 버릴 수 있다고 생각합니다 .
BoBTFish 2014-06-13

35
의 호출자가 malloc반환 된 블록의 크기를 모르기 때문에 프로그래머가 블록 크기를 올바르게 전달하도록 요구할 수 없습니다 . malloc종종 요청 된 것보다 큰 블록을 반환합니다. 기껏해야 프로그래머는 malloc()호출 에서 요청 된 크기를 전달할 수 있으므로 구현 자에게 전혀 도움이되지 않습니다 free().
Ben Voigt

답변:


97

하나의 인수 free(void *)(Unix V7에 도입 됨)는 mfree(void *, size_t)여기서 언급하지 않은 이전의 두 인수에 비해 또 다른 주요 이점이 있습니다. 하나의 인수 는 힙 메모리와 함께 작동하는 다른free 모든 API를 극적으로 단순화 합니다. 예를 들어, 메모리 블록의 크기가 필요한 경우 어떻게 든 하나 (포인터) 대신 두 개의 값 (포인터 + 크기)을 반환해야하며 C는 다중 값 반환을 단일 값 반환보다 훨씬 더 번거롭게 만듭니다. 대신 우리는 또는 다른 것을 써야 할 것 입니다 . (요즘에는 두 번째 옵션이 매우 매력적으로 보입니다. NUL로 끝나는 문자열이 "컴퓨팅 역사상 가장 치명적인 디자인 버그" 라는 것을 알고 있기 때문 입니다.freestrdupchar *strdup(char *)char *strdup(char *, size_t *)struct CharPWithSize { char *val; size_t size}; CharPWithSize strdup(char *), 그러나 그것은 뒤늦은 말입니다. 70 년대에 C의 문자열을 단순하게 처리하는 능력 char *은 실제로 Pascal 및 Algol과 같은 경쟁사에 비해 확실한 이점으로 간주되었습니다 .) 또한 strdup이 문제로 인해 고통을받는 것이 아니라 모든 시스템 또는 사용자 정의에 영향을 미칩니다. 힙 메모리를 할당하는 함수.

초기 유닉스 디자이너들은 매우 영리한 사람들이었고 기본적으로 free더 나은 이유는 여러 가지 가 있습니다 mfree. 질문에 대한 대답은 그들이 이것을 알아 채고 그에 따라 시스템을 설계했기 때문이라고 생각합니다. 그들이 그 결정을 내리는 순간 그들의 머릿속에서 무슨 일이 일어나고 있었는지에 대한 직접적인 기록을 찾을 수 있을지 의심 스럽습니다. 그러나 우리는 상상할 수 있습니다.

두 인수를 사용하여 V6 Unix에서 실행하기 위해 C로 애플리케이션을 작성한다고 가정합니다 mfree. 지금까지 잘 관리했지만 프로그램 이 더 야심 차게 되고 힙 할당 변수를 더 많이 사용해야하므로 이러한 포인터 크기를 추적하는 것이 점점 더 번거로워지고 있습니다 . 그러나 당신은 훌륭한 아이디어를 가지고 있습니다. size_t항상 이러한들을 복사하는 대신 할당 된 메모리 내부에 크기를 직접 숨기는 몇 가지 유틸리티 함수를 작성할 수 있습니다.

void *my_alloc(size_t size) {
    void *block = malloc(sizeof(size) + size);
    *(size_t *)block = size;
    return (void *) ((size_t *)block + 1);
}
void my_free(void *block) {
    block = (size_t *)block - 1;
    mfree(block, *(size_t *)block);
}

그리고 이러한 새로운 함수를 사용하여 더 많은 코드를 작성할수록 더 멋지게 보입니다. 코드를 더 쉽게 작성할 수있을 뿐만 아니라 코드를 더 빠르게 만듭니다. 두 가지가 자주 함께 사용되지 않습니다! 이들을 size_t사방에 전달하기 전에는 복사를위한 CPU 오버 헤드를 추가했고 레지스터를 더 자주 (특히 추가 함수 인수의 경우) 유출해야하고 메모리 낭비 (중첩 된 함수 호출이 종종 발생하기 때문에) size_t다른 스택 프레임에 저장된 여러 사본 ). 새 시스템에서는 여전히 메모리를 사용하여size_t,하지만 한 번만 해당되며 어디에도 복사되지 않습니다. 이것은 작은 효율성처럼 보일 수 있지만 256KiB의 RAM이있는 하이 엔드 머신에 대해 이야기하고 있음을 명심하십시오.

이것은 당신을 행복하게합니다! 그래서 당신은 다음 유닉스 릴리스에서 작업하는 수염 난 남자들과 멋진 트릭을 공유합니다. 그러나 그것은 그들을 행복하게 만들지 않고 슬프게 만듭니다. 보시다시피, 그들은과 같은 새로운 유틸리티 함수를 추가하는 과정에 strdup있었고 멋진 트릭을 사용하는 사람들이 새로운 함수를 사용할 수 없다는 것을 알고 있습니다. 새로운 함수는 모두 성가신 포인터 + 크기를 사용하기 때문입니다. API. 그리고 그것은 당신도 슬프게 만듭니다 strdup(char *). 시스템 버전을 사용할 수있는 대신 작성하는 모든 프로그램에서 좋은 기능을 직접 다시 작성해야한다는 것을 깨닫기 때문 입니다.

하지만 기다려! 이것은 1977 년이고, 이전 버전과의 호환성은 앞으로 5 년 동안 발명되지 않을 것입니다! 게다가, 아무도 심각한 실제로 사용하지 않고 자사의 오프 색상 이름이 알려지지 않은 "유닉스"일을. K & R의 초판은 현재 출판사로 향하고 있지만 문제가되지 않습니다. 첫 페이지에 "C는 문자열과 같은 복합 객체를 직접 처리하는 작업을 제공하지 않습니다. 힙이 없습니다. ... ". 역사의이 시점에서, string.h그리고 malloc벤더 확장은 (!). 따라서 Bearded Man # 1을 제안합니다. 원하는대로 변경할 수 있습니다. 왜 당신의 까다로운 할당자를 공식 할당 자로 선언하지 않습니까?

며칠 후 Bearded Man # 2는 새 API를보고 이전보다 낫다고 말합니다.하지만 여전히 크기를 저장하는 할당 당 전체 단어를 소비하고 있습니다. 그는 이것을 신성 모독의 다음으로 본다. 다른 사람들은 그가 미친 것처럼 그를 쳐다 봅니다. 그날 밤 그는 늦게 머물면서 크기를 전혀 저장하지 않는 새로운 할당자를 발명하지만 대신 포인터 값에 대해 흑 마법 비트 시프트를 수행하여 즉시 유추하고 새 API를 제자리에 유지하면서 교체합니다. 새로운 API는 아무도 스위치를 알아 차리지 못하지만 다음날 아침 컴파일러가 RAM을 10 % 적게 사용한다는 것을 알아 차립니다.

그리고 이제 모두가 행복합니다. 작성하기 쉽고 빠른 코드를 얻고, Bearded Man # 1은 strdup사람들이 실제로 사용할 수 있는 멋진 간단한 코드를 작성 하고 Bearded Man # 2는 자신이 약간의 이익을 얻었음을 확신합니다. -quines엉망으로 만드는 것으로 돌아갑니다 . 그것을 발송하십시오!

아니면 적어도 그렇게되었을 수도 있습니다.


14
어, 불분명 한 경우를 대비하여 이것은 예술적 다양성을 제공하기 위해 확증하는 세부 사항이 던져진 환상의 비행입니다. 살아 있거나 죽은 사람과의 유사점은 순전히 관련된 모든 사람 이 똑같이 보였기 때문 입니다. 실제 역사와 혼동하지 마십시오.
Nathaniel J. Smith

5
네가 이겼다. 이것은 나에게 가장 그럴듯한 설명 (그리고 최고의 글)처럼 보인다. 여기에있는 모든 것이 부정확하거나 유효하지 않은 것으로 입증 되더라도 이것은 수염을 기른 ​​남성의 훌륭한 묘사에 대한 최고의 대답입니다.
jaymmer-Monica 복원 2014-06-15

와,이 페이지의 답변은 실제로 그럴듯하게 들립니다. 나에게서 +1.
user541686

훨씬 더-실제로 즐거운이 페이지의 답변! +1도합니다.
David C. Rankin 2014

유명한 Pascal 시스템이 마이크로 컴퓨터 BASIC 인터프리터와 유사한 방식으로 가비지 수집 문자열 풀을 사용했는지 궁금합니다. C의 의미론은 그런 일과 함께 작동하지 않을 것이지만, Pascal에서는 코드가 추적 가능한 스택 프레임을 유지한다면 (어쨌든 많은 컴파일러가 수행 한) 그러한 일을 아주 잘 처리 할 수 ​​있습니다.
supercat

31

" freeC에서 해제 할 바이트 수를 사용하지 않는 이유는 무엇 입니까?"

이 없기 때문에 그것을 위해 필요, 그것은 확실히 감지하지 것이다 어쨌든.

무언가를 할당 할 때 할당 할 바이트 수를 시스템에 알려야합니다 (분명한 이유 때문에).

그러나 이미 개체를 할당 한 경우 다시 가져 오는 메모리 영역의 크기가 결정됩니다. 암묵적입니다. 그것은의 메모리를 하나 개의 연속 블록. 당신은 그것의 일부를 할당 해제 할 수 없습니다 ( realloc()그것이 어쨌든하고있는 일이 아닙니다), 당신은 단지 전체를 할당 해제 할 수 있습니다 . 당신은 "X 바이트를 할당 해제"할 수 없습니다-당신은 당신이 얻은 메모리 블록을 해제하거나 해제 malloc()하지 않습니다.

이제 해제하려면 메모리 관리자 시스템에 "여기에 포인터가 있고, free()가리키는 블록 이 있습니다."라고 말할 수 있습니다 . -메모리 관리자는 암시 적으로 크기를 알고 있거나 크기가 필요하지 않을 수도 있기 때문에이를 수행하는 방법을 알게됩니다 .

예를 들어, 대부분의 일반적인 구현은 malloc()사용 가능하고 할당 된 메모리 블록에 대한 포인터의 링크 된 목록을 유지합니다. 에 포인터를 전달 free()하면 "할당 된"목록에서 해당 포인터를 검색하고 해당 노드의 연결을 해제 한 다음 "사용 가능한"목록에 첨부합니다. 영역 크기도 필요하지 않았습니다. 잠재적으로 해당 블록을 재사용하려고 할 때만 해당 정보가 필요합니다.


내가 당신에게서 $ 100를 빌린 다음 다시 당신에게서 $ 100를 빌린 다음 다시 다섯 번하면, 당신은 내가 당신에게서 돈을 일곱 번 빌려준 것에 대해 정말로 신경 쓰나요 (실제로이자를 부과하지 않는 한!)? 아니면 내가 당신에게서 $ 700를 빌린 것에 관심이 있습니까? 여기서도 마찬가지입니다. 시스템은 할당되지 않은 메모리에만 관심이 있고 할당 된 메모리가 분할되는 방식에 대해서는 신경 쓰지 않습니다 (그리고 필요하지도 않고 그렇게해서는 안됩니다).
user541686

1
@Mehrdad : 아니요, 그렇지 않습니다. 하지만 C는 그렇습니다. 그것의 전체 목적은 사물을 (조금) 더 안전하게 만드는 것입니다. 여기서 무엇을 찾고 있는지 정말 모르겠습니다.
궤도의 경쾌함 경주

12
@ user3477950 : 바이트 수를 전달할 필요가 없습니다 . 예, 이렇게 설계 되었기 때문입니다. OP는 왜 이렇게 설계 되었습니까?
Deduplicator

5
"그럴 필요가 없기 때문에"-필요에 맞게 설계되었을 수도 있습니다.
user253751

5
@Mehrdad는 완전히 불분명하고 잘못된 비유입니다. 100 번에 4 바이트를 할당하면 어느 쪽을 비우는지가 가장 확실하게 중요합니다. 첫 번째 것을 해제하는 것은 두 번째 것을 해제하는 것과 다릅니다. 첫 번째 또는 첫 번째 차용을 상환하는 경우 그것은 중요하지 않습니다 반면에 돈으로, 그것은 단지 하나의 큰 더미입니다
user2520938

14

C는 C ++처럼 "추상적"이 아닐 수 있지만 여전히 어셈블리에 대한 추상화를위한 것입니다. 이를 위해 가장 낮은 수준의 세부 정보가 방정식에서 제외됩니다. 이렇게하면 대부분의 경우 모든 C 프로그램을 이식 할 수 없게 만드는 정렬 및 패딩에 집중할 필요가 없습니다.

요컨대, 이것이 추상화 작성의 전체 요점입니다 .


9
정렬이나 패딩이 이것과 관련이 있는지 확실하지 않습니다. 대답은 실제로 아무것도 대답하지 않습니다.
user541686

1
@Mehrdad C는 x86 언어가 아니며, 이식성을 위해 (다소) 시도하므로 프로그래머가 상당한 부담을 덜어줍니다. 어쨌든 다양한 방법 (예 : 인라인 어셈블리)으로 그 수준에 도달 할 수 있지만 추상화가 핵심입니다. 이 답변에 동의합니다.
Marco A.

4
@Mehrdad : mallocN 바이트 를 요청했고 대신 전체 페이지의 시작 부분에 대한 포인터를 반환 했다면 ( 정렬, 패딩 또는 기타 제약 으로 인해 사용자가이를 추적 할 방법이 없습니다. 그것은 역효과 것 않습니다.
마이클 Foukarakis

3
@MichaelFoukarakis : malloc할당 크기를 저장하지 않고 항상 정렬 된 포인터를 반환 할 수 있습니다. free그런 다음 적절한 정렬로 반올림하여 모든 것이 제대로 해제되도록 할 수 있습니다. 문제가 어디인지 모르겠습니다.
user541686

6
@Mehrdad : 방금 언급 한 모든 추가 작업에 대한 혜택은 없습니다. 또한 size매개 변수를 전달하면 free또 다른 버그 소스가 열립니다.
Michael Foukarakis 2014-06-13

14

사실, 고대의 유닉스 커널 메모리 할당에, mfree()했다 size인수를. malloc()사용 mfree()가능한 블록 주소 및 크기에 대한 정보를 포함하는 두 개의 어레이 (코어 메모리 용 하나, 스왑 용 하나)를 유지했습니다.

Unix V6까지 사용자 공간 할당자가 없었습니다 (프로그램은를 사용합니다 sbrk()). Unix V6에서 iolib는 할당 자 alloc(size)free()크기 인수를 사용하지 않는 호출을 포함했습니다 . 각 메모리 블록 앞에는 크기와 다음 블록에 대한 포인터가 있습니다. 포인터는 사용 가능한 블록에서만 사용되었으며 사용 가능한 목록을 탐색 할 때 사용 중 블록 메모리로 재사용되었습니다.

유닉스 32V에서와 유닉스 V7에서, 이것은 새로운 투입했습니다 malloc()free()구현, free()테이크하지 않았다 size인수를. 구현은 순환 목록이었고, 각 청크 앞에는 다음 청크에 대한 포인터와 "사용 중"(할당 된) 비트가 포함 된 단어가옵니다. 따라서 malloc()/free()명시적인 크기도 추적하지 않았습니다.


10

freeC에서 해제 할 바이트 수를 사용하지 않는 이유는 무엇 입니까?

그럴 필요가 없기 때문입니다. 이 정보는 malloc / free가 수행 한 내부 관리에서 이미 사용할 수 있습니다.

다음은 두 가지 고려 사항입니다 (이 결정에 기여했을 수도 있고 아닐 수도 있음).

  • 함수가 필요하지 않은 매개 변수를받을 것으로 예상하는 이유는 무엇입니까?

    (이는 동적 메모리에 의존하는 거의 모든 클라이언트 코드를 복잡하게 만들고 애플리케이션에 완전히 불필요한 중복성을 추가합니다). 포인터 할당을 추적하는 것은 이미 어려운 문제입니다. 관련 크기와 함께 메모리 할당을 추적하면 클라이언트 코드가 불필요하게 복잡해집니다.

  • 이 경우 변경된 free기능은 무엇을 합니까?

    void * p = malloc(20);
    free(p, 25); // (1) wrong size provided by client code
    free(NULL, 10); // (2) generic argument mismatch
    

    해제 되지 않겠습니까 (메모리 누수 원인?)? 두 번째 매개 변수를 무시 하시겠습니까? exit를 호출하여 애플리케이션을 중지 하시겠습니까? 이를 구현하면 응용 프로그램에 추가 실패 지점이 추가 될 것입니다. 필요하지 않은 기능에 대해 (필요한 경우 "응용 프로그램 수준에서 솔루션 구현"아래의 마지막 요점을 참조하십시오).

그보다는 애초에 왜 무료가 이런 식으로 만들어 졌는지 알고 싶습니다.

이것이 "적절한"방법이기 때문입니다. API는 작업을 수행하는 데 필요한 인수를 필요로하며 그 이상은 안됩니다 .

또한 해제 할 바이트 수를 명시 적으로 제공하면 일부 성능 최적화를 허용 할 수 있습니다. 예를 들어 서로 다른 할당 크기에 대해 별도의 풀을 가진 할당자는 입력 인수를보고 해제 할 풀을 결정할 수 있습니다. 전체적으로 공간 오버 헤드가 적습니다.

이를 구현하는 적절한 방법은 다음과 같습니다.

  • (시스템 수준에서) malloc 구현 내에서-라이브러리 구현자가 수신 된 크기를 기반으로 내부적으로 다양한 전략을 사용하기 위해 malloc을 작성하는 것을 막을 수는 없습니다.

  • (애플리케이션 수준에서) malloc을 래핑하고 자체 API 내에서 무료로 사용하고 대신이를 사용합니다 (애플리케이션에서 필요할 수있는 모든 곳).


6
@ user3477950 : 바이트 수를 전달할 필요가 없습니다 . 예, 이렇게 설계 되었기 때문입니다. OP는 왜 이렇게 설계 되었습니까?
Deduplicator

4
"그럴 필요가 없기 때문에"-해당 정보를 저장하지 않음으로써 필요하도록 설계되었을 수도 있습니다.
user253751

1
귀하의 요점 2에 관해서는 free (NULL)이 정의 된 행동인지 궁금합니다. 아하, "모든 표준 무 조작으로 C 라이브러리 치료 무료 (NULL)의 호환 버전"- 소스 stackoverflow.com/questions/1938735/...
Mawg 모니카 복원 말한다

10

떠오르는 다섯 가지 이유 :

  1. 편리합니다. 프로그래머의 전체 부하를 제거하고 오류를 추적하기 매우 어려운 클래스를 방지합니다.

  2. 블록의 일부를 해제 할 수있는 가능성을 열어줍니다. 그러나 메모리 관리자는 일반적으로 추적 정보를 원하기 때문에 이것이 무엇을 의미하는지 명확하지 않습니다.

  3. Orbit의 Lightness Races는 패딩과 정렬에 관한 것입니다. 메모리 관리의 특성상 할당 된 실제 크기가 요청한 크기와 상당히 다를 수 있습니다. 즉, 할당 된 실제 크기를 반환하려면 free크기와 위치 malloc를 변경해야합니다.

  4. 어쨌든 크기를 전달하는 것이 실질적인 이점이 있는지는 분명하지 않습니다. 일반적인 메모리 관리자는 크기를 포함하여 각 메모리 청크에 대해 4-16 바이트의 헤더를 가지고 있습니다. 이 청크 헤더는 할당 및 할당되지 않은 메모리에 공통적 일 수 있으며 인접 청크가 해제되면 함께 축소 될 수 있습니다. 호출자가 사용 가능한 메모리를 저장하도록 만드는 경우 할당 된 메모리에 별도의 크기 필드가 없어서 청크 당 4 바이트를 확보 할 수 있지만 호출자가 어딘가에 저장해야하기 때문에 해당 크기 필드는 얻을 수 없습니다. 그러나 이제 정보는 어쨌든 운영 효율성이 떨어질 가능성이있는 헤더 청크에 예측 가능하게 위치하지 않고 메모리에 흩어져 있습니다.

  5. 이 경우에도 이었다 더 효율적이 근본적으로 가능성이 프로그램은 시간이 해제 많은 양의 메모리를 소비하는 것 어쨌든 그래서 장점은 작은 것입니다.

덧붙여서, 다른 크기 항목에 대한 별도의 할당 자에 대한 아이디어는이 정보없이 쉽게 구현됩니다 (할당이 발생한 위치를 확인하기 위해 주소를 사용할 수 있음). 이것은 일상적으로 C ++로 수행됩니다.

나중에 추가

우스꽝스럽게도 또 다른 대답은 std :: allocatorfree이런 식으로 작동 할 수있는 증거로 제시 했지만 실제로는 왜 free이런 식으로 작동하지 않는지에 대한 좋은 예가 됩니다. malloc/ freedo와 std :: allocator가 수행하는 작업 에는 두 가지 주요 차이점 이 있습니다. 첫째, mallocfree사용자에 직면 해있다 - 그들은 작업은 일반적으로 프로그래머를 설계하고 - 반면 std::allocator표준 라이브러리에 전문 메모리 할당을 제공하도록 설계되었습니다. 이것은 첫 번째 요점이 중요하지 않거나 중요하지 않을 때의 좋은 예를 제공합니다. 라이브러리이기 때문에 추적 크기의 복잡성을 처리하는 어려움은 어쨌든 사용자에게 숨겨져 있습니다.

둘째, std :: allocator는 항상 동일한 크기의 항목으로 작동 합니다. 즉, 원래 전달 된 요소 수를 사용하여 여유 공간의 양을 결정할 수 있습니다. 이것이 free그 자체 와 다른 이유 는 예시입니다. 에서 std::allocator그들은 항상 정렬 요구 사항의 같은 종류 그래서 할당 할 항목 같은, 알려진, 크기 및 항목의 항상 같은 종류의 항상. 이것은 할당자가 처음에 이러한 항목의 배열을 단순히 할당하고 필요에 따라 처리하도록 특수화 될 수 있음을 의미합니다. 당신이 할 수없는 free대신 가끔 발신자가 *을 요청함으로써보다 큰 블록을 반환하는 것이 훨씬 더 효율적입니다, 반환에 대한 최선의 크기가 요구 크기가 있음을 보장 할 수있는 방법이 없기 때문에 하나사용자 또는 관리자는 실제로 부여 된 정확한 크기 를 추적해야합니다 . 이러한 종류의 구현 세부 정보를 사용자에게 전달하는 것은 호출자에게 도움이되지 않는 불필요한 골칫거리입니다.

-* 여전히이 점을 이해하기 어려운 사람이 있다면 다음을 고려하십시오. 일반적인 메모리 할당자는 메모리 블록의 시작 부분에 소량의 추적 정보를 추가 한 다음 여기에서 포인터 오프셋을 반환합니다. 여기에 저장된 정보에는 일반적으로 다음 사용 가능한 블록에 대한 포인터가 포함됩니다. 헤더가 4 바이트 길이 (실제로 대부분의 실제 라이브러리보다 작음)이고 크기를 포함하지 않는다고 가정하고 사용자가 16 바이트 블록을 요청하면 20 바이트의 여유 블록이 있다고 가정 해 보겠습니다. 시스템은 16 바이트 블록을 반환하지만 매번 시간을 낭비 할 수없는 4 바이트 조각을 남깁니다.malloc호출됩니다. 대신 관리자가 단순히 20 바이트 블록을 반환하면 이러한 지저분한 조각이 쌓이지 않고 사용 가능한 메모리를 더 깔끔하게 할당 할 수 있습니다. 그러나 시스템이 크기 자체를 추적하지 않고이를 올바르게 수행하려면 사용자가 모든 단일 할당에 대해 무료로 다시 전달하려면 실제로 할당 된 메모리 양을 추적해야합니다 . 동일한 인수가 원하는 경계와 일치하지 않는 유형 / 할당에 대한 패딩에 적용됩니다. 따라서, 대부분에서 필요로하는 free크기를 취할하는 중입니다 (A)는 실제로 할당 된 크기 또는 (b)와 일치하는 통과 크기에 의존 할 수없는 메모리 할당 이후 완전히 쓸모 무의미하게 추적 작업을 수행하기 위해 사용자가 필요 현실 현명한 메모리 관리자가 쉽게 처리 할 수있는 크기입니다.


# 1은 사실입니다. # 2 : 무슨 뜻인지 잘 모르겠습니다. # 3에 대해 잘 모르기 때문에 정렬에는 추가 정보를 저장할 필요가 없습니다. # 4는 순환 추론입니다. 메모리 관리자 는 크기를 저장 하기 때문에 청크 당 오버 헤드 만 필요 하므로 크기를 저장하는 이유에 대한 인수로 사용할 수 없습니다. 그리고 # 5는 매우 논쟁의 여지가 있습니다.
user541686

나는 받아 들였다가 받아 들일 수 없습니다. 이것은 좋은 대답처럼 보이지만 질문이 많은 활동을 받고있는 것 같습니다. 나는 조금 성급한 것 같습니다. 이것은 확실히 생각할 무언가를 제공합니다.
jaymmer - 분석 재개 모니카

2
@jaymmer : 예, 너무 이르다. 수락하기 전에 하루나 이틀 이상 기다리는 것이 좋으며 스스로 생각해 보는 것이 좋습니다. 이것은 정말 흥미로운 질문이며 StackOverflow의 이러한 "왜"질문에 대해 처음에 얻을 수있는 대부분의 / 모든 답변은 근본적인 질문을 실제로 해결하기보다는 현재 시스템을 정당화하려는 반자동 시도 일뿐입니다.
user541686

@Mehrdad : 당신은 # 4에서 내가 말하는 것을 오해했습니다. 나는 그것이 여분의 크기를 필요로 할 것이라고 말하는 것이 아니라 (a) 누가 크기를 저장해야하는지 움직일 것이므로 실제로 공간을 절약하지 않을 것이며 (b) 결과 변경으로 인해 실제로 만들 가능성이 있습니다 덜 효율적이지 않습니다. # 5에 관해서, 나는 그것이 논쟁의 여지가 없다고 확신하지 않습니다. 우리는-기껏해야-무료 통화에서 몇 가지 지침을 저장하는 것에 대해 이야기하고 있습니다. 사소한 무료 통화 비용에 비해.
Jack Aidley 2014-06-13

1
@Mehrdad : 아, 그리고 # 3에서는 추가 정보가 필요하지 않으며 추가 메모리가 필요합니다. 16 바이트 정렬로 작동하도록 설계된 일반적인 메모리 관리자는 115 바이트 블록을 요청하면 128 바이트 블록에 대한 포인터를 반환합니다. 경우 free통화가 해제 될 올바르게 크기를 전달하는 것입니다 그것은이를 알고 있어야합니다.
Jack Aidley 2014-06-13

5

나는 이것이 당신이 바라는 것이 아니라 그럴듯하게 올바른 유일한 것이라고 믿기 때문에 이것을 대답으로 게시하고 있습니다.

원래는 편리하다고 여겨졌지만 그 이후로는 개선 할 수 없었습니다.
그것에 대한 설득력있는 이유가 없을 것입니다. (그러나 이것이 틀렸다면 기꺼이 삭제하겠습니다.)

가능하다면 이점 이있을 것입니다 . 미리 알고있는 크기를 가진 하나의 큰 메모리 조각을 할당 한 다음, 작은 메모리 덩어리를 반복적으로 할당하고 해제하는 대신 한 번에 조금씩 해제 할 수 있습니다. 현재 이와 같은 작업은 불가능합니다.


받는 많은 (많은 1 크기를 통과하는 것은 너무 말도 생각하는 당신!)

std::allocator<T>::deallocate방법에 대한 C ++의 디자인 결정을 참조해도 될까요?

void deallocate(pointer p, size_type n);

이 가리키는 영역의 모든 물체는 이 호출 전에 파괴되어야합니다. 이 메모리를 얻기 위해 전달 된 값과 일치해야 합니다.n Tp
nallocate

이 디자인 결정을 분석 하는 데 다소 "흥미로운" 시간이 있을 것 입니다.


operator delete경우 2013 년 N3778 제안 ( "C ++ 크기 할당 해제") 도이 문제를 해결하기위한 것으로 밝혀졌습니다 .


1 원래 질문 아래의 설명을보고 매개 변수 부족을 정당화 하기 위해 "요구 된 크기는 free호출에 완전히 쓸모가 없습니다" 와 같은 성급한 주장을 한 사람이 몇 명인지 확인하십시오 size.


5
를 들어 malloc()구현 또한 기억하는 필요성을 제거 할 것을 정렬 오버 헤드에 할당 오버 헤드를 줄일 수, 할당 된 지역에 대한합니다. malloc()해제 된 청크 자체 내에서 모든 부기 작업을 수행 할 수 있습니다. 이것이 크게 개선되는 사용 사례가 있습니다. 여러 개의 작은 청크에서 큰 메모리 청크를 할당 해제하는 것은 권장되지 않지만 조각화가 크게 증가합니다.
cmaster - 분석 재개 모니카

1
@cmaster : 그 사용 사례는 제가 언급 한 것과 정확히 일치했습니다. 고마워요. 단편화와 관련하여 : 작은 청크에서 메모리를 할당하고 해제하는 대안에 비해 단편화가 어떻게 증가하는지 확실하지 않습니다.
user541686

std::allocator알려진 특정 크기의 요소 할당 합니다 . 범용 할당자가 아니며 비교는 사과와 오렌지입니다.
Jack Aidley 2014-06-14

C의 표준 라이브러리를 거의 모든 것이 빌드 될 수있는 최소한의 기본 집합으로 만들기 위해 부분적으로 철학적이며 부분적으로 디자인 결정이 내려진 것 같습니다. 원래는이 기본 접근 방식이 만드는 시스템 수준 언어 및 이식 가능하도록 의도되었습니다. 감각. C ++에서는 표준 라이브러리를 매우 광범위하게 만들기 위해 다른 결정이 내려졌습니다 (C ++ 11에서는 더 커짐). 더 빠른 개발 하드웨어, 더 큰 메모리, 더 복잡한 아키텍처 및 더 높은 수준의 애플리케이션 개발에 대한 요구가 이러한 강조 변화에 기여할 수 있습니다.
Clifford

1
@ 클리포드 : 바로 그게 제가 그럴만 한 이유가 없다고 말한 이유입니다. 내린 결정일 뿐이며 대안보다 엄격하게 낫다고 믿을 이유가 없습니다.
user541686

2

malloc과 free go는 손을 잡고 각각의 "malloc"이 하나의 "free"와 일치합니다. 따라서 이전 "malloc"과 일치하는 "free"는 단순히 해당 malloc에 ​​의해 할당 된 메모리 양을 비워야한다는 것이 합리적입니다. 이것은 99 %의 경우에 의미가있는 대부분의 사용 사례입니다. 전 세계의 모든 프로그래머가 malloc / free를 모두 사용하는 경우 프로그래머가 malloc에 ​​할당 된 양을 추적하고이를 해제해야하는 경우 모든 메모리 오류를 상상해보십시오. 당신이 말하는 시나리오는 어떤 종류의 메모리 관리 구현에서 여러 mallocs / frees를 실제로 사용하는 것이어야합니다.


5
나는 생각한다 "상상하는 모든 [...] 오류"이 같은 다른 버그 공장 생각하면 이론에 불과 gets, printf수동 루프 (오프별로 한), 정의되지 않은 행동, 서식 문자열, 암시 적 변환, 비트 트릭, 등 세라.
Sebastian Mach

1

이런 방식으로 (어떤 경우에는) 크기 정보를 수동으로 추적 할 필요가없고 프로그래머 오류가 덜 발생하는 것이 매우 편리하기 때문이라고 생각합니다.

또한, realloc에는 할당 크기 이상의 것을 포함하는이 부기 정보가 필요합니다. 즉, 작동하는 메커니즘을 구현 정의 할 수 있습니다.

제안한 방식으로 다소 작동하는 자체 할당자를 작성할 수 있으며 일반적으로 연산자 측면에서 구현되지만 특정 경우에 대해 비슷한 방식으로 풀 할당 자에 대해 C ++로 수행되는 경우가 많습니다 (잠재적으로 성능이 크게 향상됨). 풀 블록 할당을위한 새로운 기능.


1

할당 크기를 추적하지 않는 할당자가 어떻게 작동하는지 알 수 없습니다. 이렇게하지 않으면 향후 malloc요청 을 충족하기 위해 사용할 수있는 메모리를 어떻게 알 수 있습니까? 사용 가능한 메모리 블록이있는 위치를 나타 내기 위해 주소와 길이를 포함하는 일종의 데이터 구조를 적어도 저장해야합니다. (물론 여유 공간 목록을 저장하는 것은 할당 된 공간 목록을 저장하는 것과 같습니다.)


명시적인 크기 필드도 필요하지 않습니다. 다음 블록에 대한 포인터와 할당 된 비트 만 가질 수 있습니다.
ninjalj 2014-06-14

0

음, 필요한 것은 이전에 할당 한 메모리를 확보하는 데 사용할 포인터입니다. 바이트의 양은 운영 체제에서 관리하는 항목이므로 걱정할 필요가 없습니다. free ()에 의해 반환 된 할당 된 바이트 수를 얻을 필요가 없습니다. 실행중인 프로그램이 할당 한 바이트 / 위치 수를 수동으로 계산하는 방법을 제안합니다.

Linux에서 작업하고 malloc이 할당 한 바이트 / 위치의 양을 알고 싶다면 malloc을 한 번 또는 n 번 사용하고 얻은 포인터를 출력하는 간단한 프로그램을 만들 수 있습니다. 또한 프로그램을 몇 초 동안 잠자기 상태로 만들어야합니다 (다음을 수행하기에 충분 함). 그런 다음 해당 프로그램을 실행하고 PID를 찾고 cd / proc / process_PID를 작성하고 "cat maps"를 입력합니다. 출력은 특정 행에 힙 메모리 영역 (메모리를 동적으로 할당하는 메모리)의 시작 및 최종 메모리 주소를 모두 표시합니다. 할당되는 이러한 메모리 영역에 대한 포인터를 인쇄하면 할당 한 메모리 양을 추측 할 수 있습니다.

도움이 되었기를 바랍니다.


0

왜 그래야합니까? malloc () 및 free ()는 의도적으로 매우 간단한 메모리 관리 기본 요소 이며 C의 상위 수준 메모리 관리는 대부분 개발자에게 달려 있습니다. 티

게다가 realloc ()은 이미 그렇게합니다. realloc ()에서 할당을 줄이면 데이터가 이동하지 않고 반환 된 포인터가 원본과 동일합니다.

일반적으로 전체 표준 라이브러리가 응용 프로그램 요구 사항에 맞게 더 복잡한 함수를 빌드 할 수있는 간단한 기본 형식으로 구성된다는 것은 사실입니다. 따라서 "표준 라이브러리가 X를 수행하지 않는 이유"라는 형식의 질문에 대한 답은 프로그래머가 생각할 수있는 모든 작업을 수행 할 수 없기 때문에 (프로그래머의 목적) 거의 수행하지 않기 때문에 직접 빌드하거나 타사 라이브러리를 사용하십시오. 보다 유연한 메모리 관리를 포함하여보다 광범위한 표준 라이브러리를 원한다면 C ++가 답이 될 수 있습니다.

질문 C ++ 및 C에 태그를 지정하고 C ++가 사용중인 경우 어떤 경우에도 malloc / free를 거의 사용하지 않아야합니다. 새로 만들기 / 삭제를 제외하고 STL 컨테이너 클래스는 메모리를 자동으로 관리하고 가능한 방식으로 다양한 용기의 특성에 특히 적합합니다.


게다가 realloc ()은 이미 그렇게합니다. realloc ()에서 할당을 줄이면 데이터가 이동하지 않고 반환 된 포인터가 원본과 동일합니다. 이것이 보장 된 행동입니까? 여러 임베디드 할당 자에서 일반적으로 보이지만이 동작이 standard-c의 일부로 지정되었는지 확실하지 않습니다.
rsaxvc 2014-06-14

@rsaxvc : 좋은 질문 -cplusplus.com은 "새 크기가 더 크면 새로 할당 된 부분의 값이 불확실합니다."라고 문서화 합니다. , 더 작 으면 결정적 이라는 것을 의미합니다 . [opengroup.org ()는 "메모리 객체의 새로운 크기가 객체의 이동을 필요로한다면 객체의 이전 인스턴스화를위한 공간이 해제됩니다."라고 말합니다. -더 작 으면 데이터를 이동할 필요가 없습니다. 다시 말하면 더 작은 것은 재 할당되지 않을 것입니다. ISO 표준이 무엇을 말하는지 잘 모르겠습니다.
Clifford

1
realloc데이터 이동 이 절대적으로 허용됩니다. C 표준에 따르면 + + 로 구현 realloc하는 것은 완전히 합법적 입니다. 그리고 구현시 메모리 조각화를 방지하기 위해 크기가 줄어든 할당을 이동하려는 이유가 있습니다. mallocmemcpyfree
Nathaniel J. Smith
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.