할당 된 메모리에서 free ()를 사용하지 * 않아도 * 괜찮습니까?


83

저는 컴퓨터 공학을 공부하고 있고 전자 과정도 있습니다. 나는 사용하지 않도록하는 것이 가능하다는 것을 (이 과정의) 교수님의 두에서 듣고 free()(후 기능 malloc(), calloc()등)을 다시 사용하지 않을 가능성이 할당 된 메모리 공간이 다른 메모리를 할당 할 수 있기 때문이다. 즉, 예를 들어 4 바이트를 할당 한 다음 해제하면 다시 할당되지 않을 4 바이트의 공간이 생깁니다 . 구멍이 생깁니다 .

나는 그것이 미쳤다고 생각한다 : 당신은 그것을 해제하지 않고 힙에 메모리를 할당하는 장난감아닌 프로그램을 가질 수 없다 . 그러나 나는 그것이 왜 그렇게 중요한지 정확히 설명 할 지식이 없어서 각각 malloc()free().

그래서 : 사용 malloc()하지 않고 a를 사용하는 것이 적절할 수있는 상황이 free()있습니까? 그렇지 않다면 교수들에게 어떻게 설명 할 수 있습니까?


11
그것들은 "잘못된"것이 아닙니다. 그들은 매우 작은 고립 된 자유 영역의 단편화에 대해 유효한 (제한적이라면) 포인트를 가지고 있으며 아마도 여러분이보고 한 것보다 조금 더주의 깊게 언급했을 것입니다.
Chris Stratton 2014 년

2
메모리를 해제 할 필요가없는 유일한 경우는 관리되는 메모리를 사용하거나 원래 할당 된 메모리를 재사용 할 때입니다. 두 명의 강사가 이렇게 말한 이유는 메모리를 재사용 할 수있는 특정 프로그램에 대해 이야기하고 있기 때문이라고 생각합니다. 이 경우 여전히 free ()를 사용하지만 응용 프로그램의 끝에서만 사용할 수 있습니다. 이것이 그들의 의미가 아니라는 것이 확실합니까?
krowe

17
@Marian : 교수님이 C와 C ++에서 할당 된 것과 동일한 .c / .cxx 파일에 정의 된 함수에서 할당 된 메모리를 해제해야한다고 주장했습니다. 상아탑에서 너무 높게 살기 때문입니다.
PlasmaHH 2014 년

4
메모리 할당을 해제하지 않는 장난감이 아닌 프로그램이 꽤 많이 있으며, 프로세스 종료시 OS가 모든 것을 정리하도록하는 것이 많은 부기를 유지하는 것보다 훨씬 빠르므로 직접 수행 할 수 있습니다.
Donal Fellows

9
당신이들은 것을 의심없이 당신의 두뇌에 병합하지 마십시오. 저에게는 틀렸거나 구식 인 많은 교사와 강사, 교정자가있었습니다. 그리고 항상 그들이 말하는 것을 매우 정확하게 분석하십시오. 우리의 사람들은 종종 매우 정확하고 옳은 말을 할 수 있지만, 일반적인 말로만 집에 있다고 느끼는 사람이 잘못 이해하거나 잘못된 우선 순위로 이해하기 쉽습니다. 예를 들어, 학교에서 선생님이 "당신은 숙제를 했습니까?"라고 말했고 "아니오"라고 말했습니다. 내가 옳았지만 교사는 내가 예상하지 못했던 절름발이 변명을 찾을 시간을 절약했기 때문에 이러한 불쾌감을 느꼈습니다.
Sebastian Mach

답변:


100

쉬움 : 심각하지 않은 거의 모든 malloc()/free()구현 의 소스를 읽으십시오 . 이것은 호출 작업을 처리하는 실제 메모리 관리자 를 의미 합니다. 이는 런타임 라이브러리, 가상 머신 또는 운영 체제에있을 수 있습니다. 물론 모든 경우에 코드에 똑같이 액세스 할 수있는 것은 아닙니다.

인접한 구멍을 더 큰 구멍에 결합하여 메모리가 조각화되지 않도록하는 것은 매우 일반적입니다. 더 심각한 할당자는이를 보장하기 위해 더 심각한 기술을 사용합니다.

따라서 세 번의 할당 및 할당 해제를 수행하고 다음 순서로 메모리에 블록을 배치한다고 가정 해 보겠습니다.

+-+-+-+
|A|B|C|
+-+-+-+

개별 할당의 크기는 중요하지 않습니다. 그런 다음 첫 번째와 마지막 A와 C를 해제합니다.

+-+-+-+
| |B| |
+-+-+-+

마침내 B를 해제하면 (처음에는 적어도 이론적으로) 다음과 같은 결과를 얻게됩니다.

+-+-+-+
| | | |
+-+-+-+

조각 모음을 통해

+-+-+-+
|     |
+-+-+-+

즉, 하나의 더 큰 여유 블록, 남은 조각이 없습니다.

요청 된 참조 :


1
참고 자료를 제공해 주시겠습니까?
Nick

4
가상 주소 공간이 물리적 메모리의 직접적인 표현이 아니라는 점을 언급 할 가치가 있다고 생각합니다. 그리고 물리적 메모리의 조각화는 OS에서 처리 할 수 ​​있지만 프로세스에 의해 해제되지 않은 가상 메모리는 물리적으로 해제되지 않습니다.
lapk

이 가상 메모리, OS가 페이지 매핑에 생각과 최소한의 소란과에서 그것을 교환 할 수있을 것입니다 어쨌든 물리적 메모리에 1-1 매핑 드문 것 @PetrBudnik
래칫 괴물

3
매우 간결한 설명 : 개념은 잘 설명되어 있지만 실제 예제는 약간 선택되었습니다. dlmalloc의 소스 코드를보고 혼란스러워하는 사람 : 특정 크기 미만의 블록은 항상 2의 거듭 제곱이며 그에 따라 병합 / 분할됩니다. 따라서 우리는 (아마도) 8 바이트 블록 1 개와 4 바이트 블록 1 개로 끝나지만 12 바이트 블록은 없습니다. 임베디드 응용 프로그램이 오버 헤드에 더주의를 기울이려고 할 수도 있지만 이는 적어도 데스크톱에서 할당 자에 대한 꽤 표준적인 접근 방식입니다.
Voo

@Voo 예제에서 블록 크기에 대한 언급을 제거했지만 어쨌든 중요하지 않았습니다. 보다 나은?
언 와인드

42

다른 답변은 이미 설명 완벽하게 그것의 실제 구현 malloc()free()큰 무료 덩어리로 실제로 유착 (defragmnent) 구멍을한다. 그러나 그것이 사실이 아니더라도, 포기하는 것은 여전히 ​​나쁜 생각 일 것입니다 free().

문제는 프로그램이 4 바이트의 메모리를 방금 할당하고 해제하려고한다는 것입니다. 장기간 실행될 경우 4 바이트의 메모리 만 다시 할당해야 할 가능성이 높습니다. 따라서이 4 바이트가 더 큰 연속 공간으로 합쳐지지 않더라도 프로그램 자체에서 다시 사용할 수 있습니다.


6
+1 정확합니다. 문제는 free성능에 영향을 미칠 수있을만큼 충분히 호출되는 경우 ,이를 제외하면 사용 가능한 메모리에 매우 큰 흠집이 생길 정도로 충분히 호출 될 수 있습니다. 성능이 지속적으로 저하 free되지만 malloc제한된 횟수로만 호출 되는 임베디드 시스템의 상황을 상상하기 어렵 습니다. 데이터의 원샷 처리를 수행 한 다음 재설정하는 임베디드 장치를 갖는 것은 매우 드문 사용 사례입니다.
Jason C

10

예를 들어에는 많은 다른 구현이 malloc있으며 일부는 Doug Lea 또는 이것 과 같이 힙을 더 효율적으로 만들려고 시도합니다 .


9

혹시 교수님이 POSIX와 협력하고 있습니까? OS의 여가 한 번에 전체 힙을 자유롭게 - 그들은 내가 너무 나쁘지 않을 것이다이 방법을 상상할 수있는 시나리오입니다 그 작은, 최소한의 쉘 응용 프로그램을 많이 작성하는 데 사용하는 경우 입니다 을 확보보다 더 빨리가 천개의 변수. 애플리케이션이 1 ~ 2 초 동안 실행될 것으로 예상하면 할당 해제없이 쉽게 벗어날 수 있습니다.

물론 여전히 나쁜 관행입니다 (성능 향상은 항상 모호한 직감이 아닌 프로파일 링에 기반해야 함), 다른 제약 사항을 설명하지 않고 학생들에게 말해야하는 것은 아니지만 많은 작은 파이핑 쉘을 상상할 수 있습니다 -이 방식으로 작성 될 애플리케이션 (정적 할당을 완전히 사용하지 않는 경우). 변수를 해제하지 않음으로써 이익을 얻는 작업을하고 있다면, 극도로 낮은 지연 조건에서 작업하고 있거나 (이 경우 동적 할당과 C ++를 감당할 수있는 방법은 무엇입니까? : D) (단일 메모리 블록이 아니라 천 개의 정수를 차례로 할당하여 정수 배열을 할당하는 것과 같이) 매우, 매우 잘못된 작업을 수행합니다.


결국 OS가 모든 것을 해제하는 것은 성능에 관한 것이 아니라 작동하는 데 훨씬 적은 논리가 필요합니다.
hugomg 2014 년

@missingno 즉, 메모리 관리가 얼마나 어려운지 알 수 있습니다 :) 그러나 관리되지 않는 언어에 대한 논쟁으로 볼 수 있습니다. 당신을 위해 그것을 돌보는 언어 / 환경을 사용하지 마십시오.
Luaan 2014 년

5

당신은 그들이 전자 공학 교수라고 말했다. 펌웨어 / 실시간 소프트웨어를 작성하는 데 사용될 수 있으며 실행이 자주 필요한 시간을 정확하게 측정 할 수있었습니다. 이러한 경우 모든 할당에 충분한 메모리가 있다는 것을 알고 메모리를 해제하거나 재할 당하지 않으면 실행 시간에 대해 더 쉽게 계산 된 제한이 제공 될 수 있습니다.

일부 체계에서는 하드웨어 메모리 보호를 사용하여 루틴이 할당 된 메모리에서 완료되는지 확인하거나 매우 예외적 인 경우에 트랩을 생성 할 수도 있습니다 .


10
그건 좋은 지적이야. 그러나 나는 그들이 malloc그 경우에 전혀 사용하지 않을 것으로 예상하고 대신 정적 할당에 의존합니다 (또는 아마도 큰 청크를 할당 한 다음 수동으로 메모리를 처리합니다).
Luaan

2

이것을 이전의 논평자 및 답변과 다른 각도에서 취하면, 교수님이 메모리가 정적으로 할당 된 시스템 (예 : 프로그램이 컴파일 될 때)에 대한 경험이 있었을 가능성이 있습니다.

정적 할당은 다음과 같은 작업을 수행 할 때 발생합니다.

define MAX_SIZE 32
int array[MAX_SIZE];

많은 실시간 및 임베디드 시스템 (EE 또는 CE에서 발생할 가능성이 가장 높은 시스템)에서는 일반적으로 동적 메모리 할당을 모두 피하는 것이 좋습니다. 그래서,의 사용 malloc, new그리고 그들의 삭제 대응은 드물다. 게다가 컴퓨터의 메모리는 최근 몇 년 동안 폭발적으로 증가했습니다.

512MB를 사용할 수 있고 1MB를 정적으로 할당하면 소프트웨어가 폭발하기 전에 대략 511MB를 넘길 수 있습니다 (정확히는 아니지만 여기에서 나와 함께 가십시오). 남용 할 511MB가 있다고 가정 할 때, 4 바이트를 해제하지 않고 매초 malloc하면 메모리가 부족해지기 전에 거의 73 시간 동안 실행할 수 있습니다. 많은 컴퓨터가 하루에 한 번 종료된다는 점을 고려하면 프로그램의 메모리가 부족하지 않습니다!

위의 예에서 누수는 초당 4 바이트 또는 분당 240 바이트입니다. 이제 그 바이트 / 분 비율을 낮춘다 고 상상해보십시오. 이 비율이 낮을수록 프로그램이 문제없이 더 오래 실행될 수 있습니다. 당신 malloc의 s가 드물다면 그것은 실제 가능성입니다.

도대체 malloc한 번만 수행하고 malloc다시는 맞지 않을 것이라는 것을 안다면 정적 할당과 비슷하지만 할당하는 크기를 알 필요는 없습니다. 앞. 예 : 다시 512MB가 있다고 가정 해 보겠습니다. malloc32 개의 정수 배열이 필요합니다 . 이들은 각각 4 바이트의 일반적인 정수입니다. 우리는 이러한 배열의 크기가 절대 1024 개 정수를 초과하지 않는다는 것을 알고 있습니다. 프로그램에서 다른 메모리 할당은 발생하지 않습니다. 충분한 메모리가 있습니까? 32 * 1024 * 4 = 131,072. 128KB-그렇습니다. 충분한 공간이 있습니다. 더 이상 메모리를 할당하지 않을 것임을 안다면 안전하게malloc그것들을 해제하지 않고 그 배열. 그러나 이것은 프로그램이 충돌하는 경우 컴퓨터 / 장치를 다시 시작해야 함을 의미 할 수도 있습니다. 프로그램을 4,096 번 시작 / 중지하면 512MB가 모두 할당됩니다. 좀비 프로세스가있는 경우 충돌 후에도 메모리가 해제되지 않을 수 있습니다.

자신에게 고통과 불행을 저장하고 하나의 진리로이 진언 소비 : malloc해야 항상 과 관련 free. new해야 항상 있습니다 delete.


2
대부분의 임베디드 및 실시간 시스템에서 73 시간 후에 고장을 일으키는 시한 폭탄은 심각한 문제입니다.
Ben Voigt 2014 년

전형적인 정수 ??? 정수는 최소 16 비트 숫자이고 소형 마이크로 칩에서는 일반적으로 16 비트입니다. 로 일반적으로 더 많은 장치가있다 sizeof(int)이 오히려 4. 동일
ST3

2

나는 질문에 언급 된 주장이 말 그대로 프로그래머의 관점에서 취하면 말도 안된다고 생각하지만 운영 체제의 관점에서는 진실 (적어도 일부)을 가지고있다.

malloc ()은 결국 OS에서 페이지를 가져 오는 mmap () 또는 sbrk ()를 호출하게됩니다.

사소하지 않은 프로그램에서 할당 된 메모리의 대부분을 free ()하더라도 프로세스 수명 동안이 페이지가 OS에 다시 제공 될 가능성은 매우 적습니다. 따라서 free () 'd 메모리는 대부분의 경우 동일한 프로세스에서만 사용할 수 있지만 다른 프로세스에서는 사용할 수 없습니다.


2

당신의 교수는 틀린 것이 아니라 (적어도 오해의 소지가 있거나 지나치게 단순화되어 있습니다) 그렇습니다. 메모리 조각화는 성능 및 효율적인 메모리 사용에 문제를 일으키므로 때때로이를 고려하고이를 방지하기위한 조치를 취해야합니다. 한 가지 고전적인 트릭은 같은 크기의 많은 것을 할당하는 경우 시작시 해당 크기의 배수 인 메모리 풀을 확보하고 내부적으로 사용량을 완전히 관리하여 조각화가 발생하지 않도록하는 것입니다. OS 레벨 (내부 메모리 매퍼의 구멍은 해당 유형의 다음 객체에 정확히 맞는 크기입니다).

당신을 위해 그런 종류의 일을 처리하는 것 외에는 아무 일도하지 않는 전체 써드 파티 라이브러리가 있으며, 때로는 수용 가능한 성능과 너무 느리게 실행되는 것의 차이가 있습니다. malloc()그리고 free()당신이 그 (것)들에게 많이 호출하는 경우는 통보를 시작합니다 실행 시간에 띄는 양을 가져 가라.

그래서 사용하여 단지 순진 피함으로써 malloc()그리고 free()당신이 모두 분열과 성능 문제를 방지 할 수 있습니다 -하지만 당신이 바로 아래를 얻을 때, 당신은 항상 반드시 확인해야합니다 free()모든 것을 당신 malloc()이 그렇지 않으면 할 수있는 아주 좋은 이유가없는. 내부 메모리 풀을 사용하는 경우에도 좋은 응용 프로그램은 free()종료되기 전에 풀 메모리를 사용합니다. 예, OS가이를 정리하지만 나중에 애플리케이션 수명주기가 변경되면 풀이 여전히 남아 있다는 사실을 잊기 쉽습니다.

물론 장기 실행 응용 프로그램은 할당 한 모든 항목을 정리하거나 재활용하는 데 세심한주의를 기울여야합니다. 그렇지 않으면 메모리가 부족해집니다.


1

교수님들이 중요한 점을 제기하고 있습니다. 불행히도 영어 용법은 그들이 말한 내용을 절대적으로 확신하지 못합니다. 특정 메모리 사용 특성이 있고 개인적으로 작업 한 장난감이 아닌 프로그램에 대한 질문에 대답하겠습니다.

일부 프로그램은 잘 작동합니다. 그들은 반복적 인 주기로 많은 중소 규모 할당에 이어 많은 여유 공간이 뒤 따르는 웨이브 형태로 메모리를 할당합니다. 이러한 프로그램에서 일반적인 메모리 할당자는 잘 수행합니다. 그들은 해제 된 블록을 통합하고 웨이브의 끝에서 대부분의 사용 가능한 메모리는 큰 연속 청크에 있습니다. 이러한 프로그램은 매우 드뭅니다.

대부분의 프로그램은 잘못 작동합니다. 매우 작은 것부터 매우 큰 것까지 다양한 크기로 메모리를 다소 무작위로 할당 및 할당 해제하며 할당 된 블록의 높은 사용량을 유지합니다. 이러한 프로그램에서 블록을 통합하는 기능은 제한적이며 시간이 지남에 따라 매우 조각화되고 상대적으로 인접하지 않은 메모리로 완료됩니다. 32 비트 메모리 공간에서 총 메모리 사용량이 약 1.5GB를 초과하고 10MB 이상의 할당이있는 경우 결국 큰 할당 중 하나가 실패합니다. 이러한 프로그램은 일반적입니다.

다른 프로그램은 중지 될 때까지 메모리를 거의 또는 전혀 사용하지 않습니다. 실행 중에 점진적으로 메모리를 할당하여 소량 만 확보 한 다음 중지하면 모든 메모리가 해제됩니다. 컴파일러는 이와 같습니다. VM도 마찬가지입니다. 예를 들어, C ++로 작성된 .NET CLR 런타임은 아마도 메모리를 해제하지 않을 것입니다. 왜 그래야합니까?

이것이 최종 답입니다. 프로그램의 메모리 사용량이 충분히 많은 경우 malloc 및 free를 사용하여 메모리를 관리하는 것은 문제에 대한 충분한 대답이 아닙니다. 잘 동작하는 프로그램을 다룰 수있을만큼 운이 좋지 않다면 큰 메모리 청크를 미리 할당 한 다음 선택한 전략에 따라 하위 할당하는 하나 이상의 사용자 지정 메모리 할당자를 디자인해야합니다. 프로그램이 중지되는 경우를 제외하고는 무료로 사용할 수 없습니다.

교수님의 말을 정확히 알지 못한 상태에서 진정한 생산 규모 프로그램을 위해서는 아마도 그들 편이 될 것입니다.

편집하다

몇 가지 비판에 답해 보도록하겠습니다. 분명히 SO는 이런 종류의 게시물에 적합하지 않습니다. 분명하게 말하면, 저는 두 개의 컴파일러를 포함하여 이런 종류의 소프트웨어를 작성한 경험이 약 30 년입니다. 나는 학문적 언급이없고 단지 내 타박상 만 있습니다. 훨씬 좁고 짧은 경험을 가진 사람들로부터 비판이 오는 것을 느낄 수 없습니다.

내 핵심 메시지를 반복하겠습니다. malloc과 free의 균형을 맞추는 것은 실제 프로그램에서 대규모 메모리 할당에 대한 충분한 해결책 이 아닙니다 . 블록 병합은 정상이며 시간을 벌지 만 충분 하지 않습니다. 당신은 심각하고 영리한 메모리 할당자가 필요합니다.이 할당자는 메모리를 덩어리 (malloc 등을 사용하여)로 잡고 거의 무료로 사용하는 경향이 있습니다. 이것은 아마도 OP의 교수들이 염두에 두었던 메시지 일 것입니다.


1
제대로 작동하지 않는 프로그램은 적절한 할당자가 크기가 다른 청크에 대해 별도의 풀을 사용해야 함을 보여줍니다. 가상 메모리를 사용하면 서로 다른 많은 풀을 멀리 떨어져있는 것이 큰 문제가되지 않습니다. 모든 청크가 2의 거듭 제곱으로 반올림되고 모든 풀에 한 가지 크기의 둥근 청크가 포함되어 있다면 조각화가 얼마나 나빠질 수 있는지 알 수 없습니다. 최악의 경우 프로그램이 갑자기 특정 크기 범위에 대한 관심을 멈출 수 있으며, 일부는 거의 사용되지 않는 풀이 남게됩니다. 나는 이것이 매우 일반적인 행동이라고 생각하지 않습니다.
Marc van Leeuwen 2014 년

5
유능하게 작성된 프로그램은 앱이 닫힐 때까지 메모리를 확보하지 않는다는 주장에 대한 인용이 매우 많이 필요합니다.

12
이 전체 답변은 일련의 무작위 추측 및 가정처럼 읽습니다. 백업 할 것이 있습니까?
Chris Hayes

4
.NET CLR 런타임이 메모리를 해제하지 않는다는 말이 무슨 뜻인지 잘 모르겠습니다. 내가 테스트 한 한 가능하다면.
Theodoros Chatzigiannakis

1
@vonbrand : GCC에는 자체 브랜드의 가비지 수집기를 포함하여 여러 할당자가 있습니다. 패스 중에 메모리를 소비하고 패스 사이에 수집합니다. 다른 언어에 대한 대부분의 컴파일러는 최대 2 개의 패스를 가지며 패스 사이에 메모리를 거의 또는 전혀 사용하지 않습니다. 동의하지 않으시면 귀하가 제공하는 모든 예를 조사해 드리겠습니다.
david.pfx 2014 년

1

아직 아무도 을 인용하지 않았다는 사실에 놀랐습니다 .

메모리가 충분히 커져서 컴퓨터 수명 동안 여유 메모리가 부족할 수 없기 때문에 이것은 결국 사실이 아닐 수 있습니다. 예를 들어, 1 년에 약 3 ⋅ 10 13 마이크로 초가 있으므로 마이크로 초당 한 번 단점을 고려한다면 메모리 부족없이 30 년 동안 작동 할 수있는 기계를 구축 하려면 약 10 15 셀의 메모리 가 필요 합니다. 그 정도의 메모리는 오늘날의 기준으로는 엄청나게 커 보이지만 물리적으로 불가능하지는 않습니다. 반면에 프로세서는 점점 더 빨라지고 있으며 미래의 컴퓨터는 단일 메모리에서 병렬로 작동하는 많은 프로세서를 가질 수 있으므로 우리가 가정 한 것보다 훨씬 빠르게 메모리를 사용할 수 있습니다.

http://sarabander.github.io/sicp/html/5_002e3.xhtml#FOOT298

따라서 실제로 많은 프로그램이 메모리를 확보하지 않고도 잘 수행 할 수 있습니다.


1

명시 적으로 메모리를 해제하는 것이 쓸모없는 것보다 더 나쁜 경우에 대해 알고 있습니다. 즉, 프로세스 수명 이 끝날 때까지 모든 데이터가 필요할 때 입니다. 즉, 해제 할 때는 프로그램 종료 직전에만 가능합니다. 모든 최신 OS는 프로그램이 죽을 때 메모리를 해제하므로이 경우 호출 free()이 필요하지 않습니다. 실제로 메모리의 여러 페이지에 액세스해야 할 수 있으므로 프로그램 종료 속도가 느려질 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.