프로그램 수명 기간 동안 메모리를 사용해야하는 경우 프로그램 종료 직전에 메모리를 해제해야합니까?


67

많은 책과 튜토리얼에서 메모리 관리 관행이 스트레스를 받고 그것을 사용한 후에 메모리를 확보하지 않으면 신비 롭고 끔찍한 일이 일어날 것이라고 느꼈습니다.

나는 다른 시스템에 대해 말할 수는 없지만 (나에게 비슷한 관행을 채택한다고 가정하는 것이 합리적이지만) 적어도 Windows에서는 커널이 기본적으로 사용하는 대부분의 리소스 (홀수 소수 제외)를 정리하도록 보장됩니다 프로그램 종료 후 프로그램. 여기에는 다양한 것들 중에서 힙 메모리가 포함됩니다.

사용자가 파일을 사용할 수 있도록 파일을 사용한 후에 파일을 닫으려는 이유 또는 대역폭을 절약하기 위해 서버에 연결된 소켓의 연결을 끊고 싶은 이유를 이해하지만 어리석은 것처럼 보입니다. 프로그램에서 사용하는 모든 메모리를 미세 관리해야합니다.

지금, 나는이 질문은 당신이 필요로 얼마나 많은 메모리를 기반으로 당신이 당신의 기억을 처리하는 방법부터 다양한 것을 동의하고 당신이 그것을 필요로 할 때, 그래서이이 질문의 범위를 좁힐 것이다 : 나는의 조각을 사용해야하는 경우 내 프로그램 수명 동안 메모리가 부족한 경우 프로그램 종료 직전에 메모리를 해제해야합니까?

편집 : 복제본으로 제안 된 질문은 Unix 제품군 운영 체제에만 해당됩니다. 최고 답변은 Linux에만 해당되는 툴 (예 : Valgrind)도 지정했습니다. 이 질문은 대부분의 "일반"비 임베디드 운영 체제를 다루고 프로그램 수명 기간 동안 필요한 메모리를 확보하는 것이 좋은 방법이 아닌 이유입니다.



19
이 언어에 관계없이 태그를 지정했지만 많은 언어 (예 : java)에서 메모리를 수동으로 해제 할 필요는 없습니다. 객체로의 마지막 참조가 범위를 벗어나 후에는 자동으로 시간을 일
리처드 설렘을

3
물론 단일 삭제없이 C ++을 작성할 수 있으며 메모리에 적합합니다.
Nikko

5
@RichardTingle C 및 C ++ 이외의 다른 언어를 생각할 수는 없지만 언어에 구애받지 않는 태그는 가비지 수집 유틸리티가 많이 내장되어 있지 않은 모든 언어를 포괄합니다. 하지만 요즘에는 드문 일입니다. 이제 C ++에서 이러한 시스템을 구현할 수 있다고 주장 할 수는 있지만 여전히 메모리 조각을 삭제하지 않을 수 있습니다.
CaptainObvious

4
"커널은 기본적으로 프로그램 종료 후 모든 리소스 [...]를 정리하도록 보장됩니다." 모든 것이 메모리, 핸들 또는 커널 객체가 아니기 때문에 일반적으로 잘못된 것입니다. 그러나 당신이 즉시 질문을 제한하는 기억은 사실입니다.
Eric Towers

답변:


108

프로그램 수명 기간 동안 메모리를 사용해야하는 경우 프로그램 종료 직전에 메모리를 해제해야합니까?

필수는 아니지만 몇 가지 단점뿐만 아니라 이점도있을 수 있습니다.

프로그램이 실행 시간 동안 메모리를 한 번 할당하고 프로세스가 끝날 때까지 메모리를 해제하지 않으면 메모리를 수동으로 해제하지 않고 OS에 의존하지 않는 것이 현명한 방법 일 수 있습니다. 내가 아는 모든 최신 OS에서 이것은 안전합니다. 프로세스가 끝나면 할당 된 모든 메모리가 시스템에 안정적으로 반환됩니다.
경우에 따라 할당 된 메모리를 명시 적으로 정리하지 않으면 정리를 수행하는 것보다 훨씬 빠를 수도 있습니다.

그러나 실행이 끝날 때 모든 메모리를 명시 적으로 해제하면

  • 디버깅 / 테스트 중 mem leak detection 도구는 "false positives"를 표시하지 않습니다
  • 할당 및 할당 해제와 함께 메모리를 사용하는 코드를 별도의 구성 요소로 옮기고 나중에 구성 요소의 사용자가 메모리 사용 시간을 제어해야하는 다른 컨텍스트에서 사용하는 것이 훨씬 쉬울 수 있습니다.

프로그램의 수명은 바뀔 수 있습니다. 아마도 귀하의 프로그램은 오늘날 일반적인 수명이 10 분 미만인 작은 명령 줄 유틸리티 일 수 있으며 10 초마다 kb의 일부로 메모리를 할당하므로 프로그램이 종료되기 전에 할당 된 메모리를 전혀 확보 할 필요가 없습니다. 나중에 프로그램이 변경되고 수명이 몇 주인 서버 프로세스의 일부로 연장 된 사용을 얻습니다. 따라서 사용되지 않은 메모리를 해제하지 않는 것은 더 이상 옵션이 아닙니다. . 즉, 전체 프로그램을 검토 한 후 할당 해제 코드를 추가해야합니다. 운이 좋으면 쉬운 일이지만 그렇지 않은 경우 너무 어려워서 장소를 놓칠 가능성이 높습니다. 그리고 당신이 그 상황에있을 때, 당신은 당신이 "무료"를 추가했으면 좋겠다

더 일반적으로, 쓰기 할당하고 많은 프로그래머들 사이에서 "좋은 습관"항상 관련 할당 해제 코드 페어 카운트 : 항상 이렇게하면 메모리 상황에 해제 코드를 잊어 확률이 감소 한다 해제합니다.


12
좋은 프로그래밍 습관 개발에 대한 좋은 지적.
Lawrence

4
일반적으로이 조언에 강력하게 동의합니다. 기억과 함께 좋은 습관을 유지하는 것이 매우 중요합니다. 그러나 예외가 있다고 생각합니다. 예를 들어, 당신이 할당 한 것이 통과하고 "적절하게"해제하는 데 몇 초가 걸리는 미친 그래프라면 프로그램을 끝내고 OS가 핵을 사용하게함으로써 사용자 경험을 향상시킬 것입니다.
GrandOpener

1
모든 최신 "일반"(메모리 보호 기능이 내장되지 않은) OS에서 안전하며 그렇지 않은 경우 심각한 버그가됩니다. 권한이없는 프로세스가 OS에서 회수하지 않는 메모리를 영구적으로 잃을 수있는 경우 여러 번 실행하면 시스템의 메모리가 부족해질 수 있습니다. OS의 장기적인 건강 상태는 권한이없는 프로그램의 버그 부족에 의존 할 수 없습니다. (물론 이것은 스왑 공간으로 만 지원되는 Unix 공유 메모리 세그먼트와 같은 것을 무시하고 있습니다.)
Peter Cordes

7
@GrandOpener이 경우이 트리에 대해 일종의 지역 기반 할당자를 사용하여 일반적인 방법으로 할당하고 시간이 다가 오면 한 번에 전체 지역을 할당 해제하고 해제하는 대신 할당 해제 할 수 있습니다. 조금씩. 그것은 여전히 ​​"적절한"것입니다.
Thomas

3
또한 메모리가 프로그램의 전체 수명 동안 실제로 존재해야하는 경우 스택에 구조를 만드는 것이 현명한 대안이 될 수 있습니다 (예 : in) main.
Kyle Strand

11

프로그램 실행이 끝날 때 메모리를 비우는 것은 CPU 시간 낭비입니다. 마치 궤도에서 핵을 파기 전에 집을 정리하는 것과 같습니다.

그러나 때로는 짧은 실행 프로그램이 훨씬 오래 실행되는 프로그램의 일부로 바뀔 수 있습니다. 그런 다음 물건을 풀어야합니다. 이것이 어느 정도 생각되지 않았다면 상당한 재 작업이 필요할 수 있습니다.

이에 대한 한 가지 현명한 해결책은 "talloc"입니다.이 기능을 사용하면 많은 메모리 할당을 수행 한 다음 한 번의 호출로 모든 메모리 할당을 버릴 수 있습니다.


1
OS에 자체 누출이 없다고 가정합니다.
WGroleau

5
"CPU 시간 낭비"비록 매우 작은 시간이지만. free일반적으로보다 훨씬 빠릅니다 malloc.
Paul Draper

@PaulDraper Aye, 모든 것을 다시 바꾸는 시간 낭비는 훨씬 더 중요합니다.
중복 제거기

5

가비지 콜렉션이 있는 언어 (예 : Scheme, Ocaml, Haskell, Common Lisp 및 Java, Scala, Clojure)를 사용할 수 있습니다.

(대부분의 GC-ED의 언어에서이없는 방법 하는 명시 적수동 ! 때때로, 일부 값이 될 수있는 메모리 확정 , 예를 들면 GC와 런타임 시스템 만이 아닌, 그 값에 도달 할 때 파일 핸들 값을 닫을 것이 확실하고 신뢰할 수 없으며 대신 최종 처리가 보장되지 않기 때문에 파일 핸들을 명시 적으로 닫아야 합니다.

C (또는 C ++)로 코딩 된 프로그램 경우 Boehm의 보수 가비지 수집기를 사용할 수도 있습니다 . 당신은 모든 당신 대체 할 malloc함께 GC_malloc 약 귀찮게하지 free어떤 포인터를 -ing. 물론 Boehm의 GC 사용의 장단점을 이해해야합니다. GC 핸드북을 읽으십시오 .

메모리 관리는 프로그램의 글로벌 속성입니다. 어떤 식 으로든 전체 프로그램 속성이기 때문에 (그리고 주어진 데이터의 생동감) 구성이 아니며 모듈이 아닙니다.

마지막으로, 다른 사람들이 지적했듯이 free힙 할당 C 메모리 영역을 명시 적으로 지정하는 것이 좋습니다. 많은 메모리를 할당하지 않는 장난감 프로그램의 경우 메모리가 전혀 사용되지 않도록 결정할 수도 있습니다 free( 프로세스 가 종료되면 가상 주소 공간을 포함한 자원 이 운영 체제에 의해 해제 됨).

프로그램 수명 기간 동안 메모리를 사용해야하는 경우 프로그램 종료 직전에 메모리를 해제해야합니까?

아니요, 그렇게 할 필요는 없습니다. 그리고 많은 실제 프로그램은 전체 수명에 필요한 일부 메모리를 해제하지 않습니다 (특히 GCC 컴파일러는 일부 메모리를 해제하지 않습니다). 그러나 그렇게 할 때 (예를 들어 C 동적으로 할당 된free 특정 데이터 조각을 귀찮게하지 않음 ) 동일한 프로젝트에서 미래 프로그래머의 작업용이하게 하기 위해 그 사실을 더 잘 언급 할 것 입니다. 사용되지 않는 메모리의 양은 제한되어 있고 사용 된 총 힙 메모리에 비해 상대적으로 적은 양을 유지하는 것이 좋습니다.

시스템은 free종종 (예를 들어 POSIX 시스템에서 munmap (2) 를 호출하여) OS에 메모리를 해제하지 않지만 대개 메모리 영역을 future에서 재사용 가능한 것으로 표시합니다 malloc. 특히 가상 주소 공간 (예 : /proc/self/mapsLinux에서 볼 때 proc (5) .... 참조)은 이후에 줄어들지 않을 수 있습니다 free(따라서 유틸리티 는 프로세스에 사용 된 메모리와 같은 양을 사용 ps하거나 top보고합니다).


3
"때로는 일부 값이 확정 될 수 있습니다. 예를 들어 GC 및 런타임 시스템은 해당 값에 도달 할 수 없을 때 파일 핸들 값을 닫습니다."대부분의 GC 언어에서 메모리가 회수 될 것이라는 보장은 없으며 종료시에도 종료자가 실행됩니다 : stackoverflow.com/questions/7880569/…
중복 제거기

저는 개인적으로이 답변을 선호합니다. GC (즉,보다 자동화 된 접근 방식)를 사용하도록 권장하기 때문입니다.
Ta Thanh Dinh

3
@tathanhdinh 메모리 전용이지만 더 자동화되었습니다. 다른 모든 리소스에 대해서는 완전 수동입니다. GC는 편리한 메모리 처리를 위해 결정 성과 메모리를 교환하여 작동합니다. 그리고 파이널 라이저는 많은 도움이되지 않으며 자체 문제가 있습니다.
중복 제거기

3

그것은하지 않습니다 필요 당신은 당신이 실패 제대로 경우 프로그램을 실행하지 않을 것 같이. 그러나 기회가 주어지면 선택할 수있는 이유가 있습니다.

내가 반복적으로 접하는 가장 강력한 사례 중 하나는 누군가가 실행 파일에서 실행되는 작은 시뮬레이션 코드를 작성한다는 것입니다. "이 코드를 시뮬레이션에 통합하고 싶다"고 말합니다. 그런 다음 몬테카를로 달리기 사이에 다시 초기화하는 방법을 물어보고 그들은 나를 빈틈없이 바라 봅니다. "재 초기화 란 무엇을 의미합니까? 새로운 설정으로 프로그램을 실행하기 만하면됩니까?"

때때로 클린업으로 인해 소프트웨어를 훨씬 쉽게 사용할 수 있습니다. 많은 예제의 경우 무언가를 정리할 필요가 없다고 가정하고 해당 추정에 대한 데이터 및 수명을 처리하는 방법에 대해 가정합니다. 이러한 추정이 유효하지 않은 새로운 환경으로 이동하면 전체 알고리즘이 더 이상 작동하지 않을 수 있습니다.

얼마나 이상한 일이 생길 수 있는지에 대한 예를 보려면 프로세스 종료시 관리되는 언어가 마무리 작업을 처리하는 방법 또는 C #이 응용 프로그램 도메인의 프로그래밍 중지를 처리하는 방법을 살펴보십시오. 이러한 극단적 인 경우에 균열을 겪는 가정이 있기 때문에 그들은 매듭으로 묶습니다.


1

어쨌든 수동으로 메모리를 비우지 않는 언어를 무시하는 중 ...

지금 "프로그램"으로 생각하는 것은 어느 시점에서 더 큰 프로그램의 일부인 함수 또는 메소드가 될 수 있습니다. 그런 다음 해당 함수가 여러 번 호출 될 수 있습니다. 그런 다음 "수동으로 해제"해야하는 메모리는 메모리 누수가됩니다. 물론 그것은 심판의 소명입니다.


2
이것은 단지 몇 시간 전에 게시 된 최고의 답변 에서 반복 된 요점 (그리고 훨씬 더 잘 설명 된 것)을 반복하는 것 같습니다 . 메모리의 사용 시간이 컴포넌트의 사용자에 의해 제어되어야하는 다른 상황에서 ... "
gnat

1

언젠가는 프로그램을 변경하고 다른 프로그램과 통합하거나 여러 인스턴스를 순서대로 또는 병렬로 실행하고 싶을 가능성이 매우 높습니다. 그런 다음 수동으로이 메모리를 비워야하지만 더 이상 상황을 기억하지 못하므로 프로그램을 다시 이해하는 데 시간이 더 걸립니다.

그들에 대한 당신의 이해가 여전히 신선하면서 일을하십시오.

미래에 큰 수익을 낼 수있는 작은 투자입니다.


2
이것은 이전 11 답변에서 만들어지고 설명 된 점보다 실질적인 것을 추가하지 않는 것 같습니다. 특히, 향후 프로그램 변경 가능성에 대한 요점은 이미 3-4 회 이루어졌다
gnat

1
@gnat 복잡하고 모호한 방식으로-그렇습니다. 명확한 진술로-아니오. 속도가 아니라 응답 품질에 집중합시다.
Agent_L

1
현명한 품질, 최고의 답변 이이 점을 설명하는 데 훨씬 더 나은 것으로 보인다
gnat

1

아니요, 필요하지는 않지만 좋은 생각입니다.

"사용이 끝난 후에 메모리를 확보하지 않으면 신비 롭고 끔찍한 일이 일어날 것" 이라고 생각 합니다.

기술적 인 측면에서, 이것의 유일한 결과는 하드 한계에 도달하거나 (예 : 가상 주소 공간이 모두 소모 됨) 성능이 수용 할 수 없게 될 때까지 프로그램이 더 많은 메모리를 계속 사용한다는 것입니다. 프로그램이 종료 되려고한다면 프로세스가 실제로 존재하지 않기 때문에이 중 어느 것도 중요하지 않습니다. "신비하고 끔찍한 것"은 순전히 개발자의 정신 상태에 관한 것입니다. 메모리 누수의 원인을 찾는 것은 절대적인 악몽이 될 수 있으며 (이것은 과소 평가입니다), 누수가없는 코드를 작성하려면 많은 기술과 훈련이 필요합니다. 이 기술과 훈련을 발전시키기 위해 권장되는 접근법 은 프로그램이 종료 되더라도 더 이상 필요하지 않은 메모리 를 항상 확보 하는 것입니다.

물론 이것은 다른 사람들이 말했듯이 코드를 더 쉽게 재사용하고 조정할 수 있다는 이점이 있습니다.

그러나 프로그램 종료 직전에 메모리를 비우지 않는 것이 더 좋은 경우가 적어도 하나 있습니다.

수백만 개의 작은 할당을했으며 대부분 디스크로 스왑 된 경우를 고려하십시오. 모든 것을 해제하기 시작하면 부기 정보에 액세스 할 수 있도록 데이터를 즉시 폐기하기 위해 대부분의 메모리를 RAM으로 다시 교체해야합니다. 이렇게하면 프로그램을 종료하는 데 몇 분이 걸릴 수 있습니다! 말할 것도없이 그 시간 동안 디스크와 물리적 메모리에 많은 압력을가했습니다. 물리적 메모리가 부족한 경우 (다른 프로그램이 많은 메모리를 씹기 때문에 프로그램이 닫혀있을 수 있음) 여러 개체를 해제해야 할 때 개별 페이지를 여러 번 교체해야 할 수 있습니다. 같은 페이지이지만 연속적으로 해제되지는 않습니다.

대신 프로그램이 중단되면 OS는 디스크로 스왑 된 모든 메모리를 단순히 버립니다. 디스크 액세스가 필요하지 않기 때문에 거의 즉각적입니다.

OO 언어에서는 객체의 소멸자를 호출하면 메모리가 강제로 스왑됩니다. 이 작업을 수행해야 할 경우 메모리를 비울 수도 있습니다.


1
할당을 해제하기 위해 페이징 된 메모리를 페이징해야한다는 아이디어를 뒷받침 할만한 내용이 있습니까? 그것은 분명히 비효율적이며, 확실히 현대 OS는 그보다 똑똑합니다!

1
@Jon of All Trades에서 현대 OS는 똑똑하지만 아이러니하게도 가장 현대적인 언어 는 그렇지 않습니다. free (무언가)를하면 컴파일러는 스택에 "무언가"를 놓고 free ()를 호출합니다. 스택에 넣으려면 스왑 아웃 된 경우 다시 RAM으로 스왑해야합니다.
Jeffiekins

무료 목록 인 @JonofAllTrades는 그 효과가있을 것입니다. 그것은 꽤 쓸모없는 malloc 구현입니다. 그러나 OS는 이러한 구현을 사용하지 못하게 할 수 없습니다.

0

수동으로 정리하는 주요 이유는 다음과 같습니다. 종료시 정리할 메모리 블록에 대해 실제 메모리 누수를 착각 할 가능성이 적으며, 전체 데이터 구조를 수행 할 때만 할당 자에서 버그를 잡을 수 있습니다. 프로그램을 종료하기 전에 일부 객체 할당 해제되어야하기 때문에 리팩토링하면 두통이 훨씬 작아집니다 .

수동으로 정리하지 않는 주된 이유는 성능, 성능, 성능 및 불필요한 정리 코드에서 무료로 두 번 또는 무료로 사용 가능한 버그가 발생할 가능성이 있기 때문에 크래시 버그 또는 보안으로 바뀔 수 있습니다. 공적.

성능에 관심이 있다면 항상 추측하는 대신 항상 낭비하는 위치를 파악하기 위해 프로파일 링을 원합니다. 선택적인 정리 코드를 조건부 블록에 싸서 디버깅 할 때 남겨두면 코드 작성 및 디버깅의 이점을 얻을 수 있으며 경험적으로 결정된 경우에만 오버 헤드가 발생하면 최종 실행 파일에서이를 건너 뛰도록 컴파일러에 지시하십시오. 그리고 프로그램을 폐쇄하는 데있어 지연은 거의 정의상 거의 중요하지 않습니다.

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