C 애플리케이션을 종료하면 malloc-ed 메모리가 자동으로 해제됩니까?


93

다음 C 코드가 있다고 가정 해 보겠습니다.

int main () {
  int *p = malloc(10 * sizeof *p);
  *p = 42;
  return 0;  //Exiting without freeing the allocated memory
}

C 프로그램을 컴파일하고 실행할 때, 즉 메모리에 일부 공간을 할당 한 후 응용 프로그램을 종료하고 프로세스가 종료 된 후에도 할당 한 메모리가 계속 할당됩니까 (즉, 기본적으로 공간을 차지합니까)?


9
메모리를 정리하는 것이 "좋은 스타일"입니다. 보호 된 메모리가없는 OS (아래의 주요 제안)에서 실행할 수 있기 때문이 아니라 메모리 누수를 발견하고 유지하기 때문입니다. 당신의 코드는 간결하고 정확합니다 ...
Matt Joiner

답변:


113

운영 체제에 따라 다릅니다. 대부분의 최신 (및 모든 주요) 운영 체제는 프로그램이 종료 될 때 해제되지 않은 메모리를 해제합니다.

이것에 의존하는 것은 나쁜 습관이며 명시 적으로 해제하는 것이 좋습니다. 문제는 코드가 나쁘다는 것만이 아닙니다. 작은 프로그램을 더 크고 오래 실행되는 프로그램에 통합하기로 결정할 수 있습니다. 그런 다음 잠시 후 메모리 누수를 추적하는 데 몇 시간을 소비해야합니다.
운영 체제의 기능에 의존하면 코드의 이식성이 떨어집니다.


16
한 번 임베디드 플랫폼에서 win98을 만났고 그 경험을 바탕으로 프로그램을 닫을 때 메모리를 해제하지 않는다고 말할 수 있습니다.
San Jacinto

8
@Ken 예였습니다. 또한 YAGNI와 엉성한 코딩 사이에는 경계가 있습니다. 자원을 확보하지 않으면이를 가로지 릅니다. YAGNI 원칙은 프로그램을 올바르게 작동시키는 코드가 아닌 기능에 적용하기위한 것이기도합니다. (메모리를 해제하지 않는 것은 버그입니다).
Yacoby 2010

5
+1 : 고려해야 할 가장 중요한 점은 메모리 관리가 Yacoby가 "운영 체제의 기능"이라고 정확히 말한대로 라는 것 입니다. 내가 착각하지 않는 한, 프로그래밍 언어는 프로그램 실행 전후에 일어나는 일을 정의하지 않습니다.
D.Shawley 2010

9
메모리를 수동으로 해제하려면 더 많은 시간이 걸리고 더 많은 코드가 필요하며 버그가 발생할 가능성이 있습니다 (할당 해제 코드에서 버그를 본 적이 없다고 말해주세요!). 특정 사용 사례에 대해 모든면에서 더 나쁜 것을 의도적으로 생략하는 것은 "엉성한"것이 아닙니다. 프로세스 종료 후 페이지를 비울 수 없거나 더 큰 프로그램 (YAGNI)에 통합 할 수없는 오래된 / 작은 시스템에서 실행하려는 경우를 제외하고는 순 손실처럼 보입니다. 스스로 청소하지 않는다고 생각하는 것이 프로그래머의 자존심을 상하게한다는 것을 알고 있지만, 실제로 어떤 방식으로 더 나은가?

6
SO에서 메모리 누수를 제안하는 사람은 모든 평판과 배지를 제거해야합니다
Ulterior

53

일반적으로 최신 범용 운영 체제는 프로세스가 종료 된 후 정리합니다 . 대체 방법은 시스템이 시간이 지남에 따라 리소스를 잃고 제대로 작성되지 않았거나 리소스를 누출하는 버그가 거의 발생하지 않는 프로그램으로 인해 재부팅이 필요하기 때문에 필요합니다.

어쨌든 프로그램이 리소스를 명시 적으로 해제하는 것은 다음과 같은 다양한 이유로 좋은 습관이 될 수 있습니다 .

  • 임시 파일이나 외부 리소스 상태 변경 과 같이 종료시 OS에 의해 정리 되지 않는 추가 리소스가있는 경우 종료시 이러한 모든 작업을 처리하는 코드가 필요합니다. 종종 메모리 해제와 우아하게 결합됩니다.
  • 프로그램의 수명이 길어지기 시작하면 메모리를 해제하는 유일한 방법이 종료되는 것을 원하지 않을 것 입니다. 예를 들어, 프로그램을 개별 작업 단위에 대한 많은 요청을 처리하는 동안 계속 실행되는 서버 (데몬)로 변환하거나 프로그램이 더 큰 프로그램의 작은 부분이 될 수 있습니다.

그러나 메모리 확보를 건너 뛰는 이유는 효율적인 종료 입니다. 예를 들어 애플리케이션에 메모리에 큰 캐시가 있다고 가정합니다. 종료 될 때 전체 캐시 구조를 통과하여 한 번에 하나씩 해제하면 유용한 목적이없고 리소스가 낭비됩니다. 특히, 캐시가 포함 된 메모리 페이지가 운영 체제에 의해 디스크로 스왑 된 경우를 고려하십시오. 구조를 살펴보고 해제 함으로써 모든 페이지를 한꺼번에 메모리로 되돌리고 실제 이익을 위해 상당한 시간과 에너지를 낭비하고 시스템의 다른 프로그램이 교체 될 수도 있습니다!

관련 예로서 각 요청에 대한 프로세스를 생성 한 다음 완료되면 종료되도록하는 고성능 서버가 있습니다. 즉 , 프로세스가 끝날 때 모든 것이 운영 체제의 사용 가능한 메모리로 다시 사라지기 때문에 메모리 할당 을 추적 할 필요도없고 해제 또는 가비지 수집을 전혀 수행하지 않습니다. (사용자 지정 메모리 할당자를 사용하여 프로세스 내에서 동일한 종류의 작업을 수행 할 수 있지만 매우 신중한 프로그래밍이 필요합니다. 본질적으로 OS 프로세스 내에서 "경량 프로세스"에 대한 자신의 개념을 만들어야합니다.)


11

이 스레드에 마지막 게시물을 올린 후 너무 오래 게시 한 것에 대해 사과드립니다.

추가 포인트 하나. 모든 프로그램이 정상적으로 종료되는 것은 아닙니다. 충돌 및 ctrl-C 등으로 인해 프로그램이 제어되지 않은 방식으로 종료됩니다. OS가 힙을 해제하지 않고, 스택을 정리하고, 정적 변수를 삭제하는 등의 작업을 수행하지 않으면 결국 시스템이 메모리 누수로 인해 충돌하거나 더 나빠질 수 있습니다.

이 외에도 흥미롭게도 우분투에서 충돌 / 중단이 발생하고 다른 모든 최신 OS에는 "처리 된"리소스에 문제가 있다고 생각합니다. 소켓, 파일, 장치 등은 프로그램이 종료 / 충돌 될 때 "열려있는"상태로 유지 될 수 있습니다. 또한 정상 종료 전에 정리의 일부로 "핸들"또는 "설명자"로 모든 항목을 닫는 것이 좋습니다.

현재 소켓을 많이 사용하는 프로그램을 개발 중입니다. 교수형에 갇 히면 ctrl-c를 눌러 소켓을 좌초시켜야합니다. 모든 열린 소켓 목록과 sigint 및 sigterm을 포착하는 sigaction 핸들러를 수집하기 위해 std :: vector를 추가했습니다. 핸들러는 목록을 살펴보고 소켓을 닫습니다. 나는 조기 종료로 이어질 던지기 전에 사용할 유사한 정리 루틴을 만들 계획입니다.

이 디자인에 대해 언급하고 싶은 사람이 있습니까?


1
소켓 리소스를 남겨 두는 프로그램이 있었고 우분투 시스템은 2 주마다 재부팅해야했고 메모리가 부족해지기 시작했고 메모리도 충분했기 때문에 이렇게 말씀하셨습니다. 시스템 리소스를 정리하는 것을 잊으면 시스템 리소스가 손상되었는지 확실하지 않습니다.
octopusgrabbus

8
Stackoverflow는 포럼이 아닙니다. 오래된 질문에 답하는 데 아무런 문제 가 없습니다 . meta.stackexchange.com/questions/20524/reviving-old-questions
mk12

6

여기서 일어나는 일은 ( 최신 OS에서 ) 프로그램이 자체 "프로세스"내에서 실행된다는 것입니다. 이것은 자체 주소 공간, 파일 설명자 등이 부여 된 운영 체제 엔터티입니다. malloc호출은 "힙"또는 프로세스에 할당 된 할당되지 않은 메모리 페이지에서 메모리를 할당합니다.

이 예에서와 같이 프로그램이 종료되면 프로세스에 할당 된 모든 리소스가 운영 체제에 의해 재활용 / 폐기됩니다. 메모리의 경우 사용자에게 할당 된 모든 메모리 페이지는 단순히 "사용 가능"으로 표시되고 다른 프로세스에서 사용할 수 있도록 재활용됩니다. 페이지는 malloc이 처리하는 것보다 낮은 수준의 개념입니다. 결과적으로 malloc / free의 세부 사항은 모든 것이 정리됨에 따라 모두 사라집니다.

랩톱 사용을 마치고 친구에게주고 싶을 때 각 파일을 개별적으로 삭제하지 않아도되는 것과 도덕적으로 동일합니다. 하드 드라이브를 포맷하기 만하면됩니다.

이 모든 것은 다른 모든 응답자가 지적했듯이 이것에 의존하는 것은 좋은 습관이 아닙니다.

  1. 항상 리소스를 관리하도록 프로그래밍해야하며 C에서는 메모리도 의미합니다. 결국 라이브러리에 코드를 임베드하거나 예상보다 훨씬 오래 실행될 수 있습니다.
  2. 일부 OS (오래된 OS 및 일부 최신 임베디드 OS)는 이러한 하드 프로세스 경계를 ​​유지하지 않을 수 있으며 할당은 다른 주소 공간에 영향을 미칠 수 있습니다.

4

예. OS가 리소스를 정리합니다. 음 ... NetWare의 이전 버전은 그렇지 않았습니다.

편집 : San Jacinto가 지적했듯이이를 수행하지 않는 시스템 (NetWare 제외)이 확실히 있습니다. 일회용 프로그램에서도 나는 습관을 유지하기 위해 모든 자원을 자유롭게하는 습관을들이려고 노력합니다.


3
나는 반대표를 던지지 않지만 이것은 후손에게 꽤 위험한 게시물입니다. DOS는 여전히 많은 임베디드 플랫폼에서 사용되며 메모리 정리를 수행하는 것이 확실하지 않습니다. 포괄적 인 일반화는 잘못되었습니다.
San Jacinto

@San Jacinto : 좋은 지적입니다. 이것이 내가 NetWare 참조를 만든 이유이지만 아마도 설명을 사용할 수 있습니다. 조금 수정하겠습니다.
Mark Wilkins

3
@San DOS는 멀티 태스킹 OS가 아닙니다. DOS 프로그램 (TSR 제외)이 종료되면 다음 프로그램을로드 할 때 모든 메모리를 사용할 수 있습니다.

@Neil은 알림을 보내 주셔서 감사하지만, 임베디드 시스템의 일반적인 사용과 마찬가지로 이벤트가 발생하면 시작되는 TSR과 같은 프로그램을 언급했습니다. 그럼에도 불구하고 귀하의 전문성과 제가 실패한 부분을 명확히 해주셔서 감사합니다. :)
San Jacinto

2

예, 운영 체제는 프로세스가 종료되면 모든 메모리를 해제합니다.


왜 이것이 반대표를 받았는지 모르겠습니다. malloc의 메모리는 프로세스가 죽을 때 해제 될 것입니다 (malloc의 wikipedia 정의에 따르면)
Arve

7
Wikipedia는 존재하는 모든 OS의 매뉴얼이 아닙니다. 대부분의 최신 OS는 메모리를 회수하지만 모두 (특히 모든 구형 OS는 아님) 메모리를 회수합니다. 거기에 malloc덧붙여, C가 메모리로 무엇을할지 약속 할 수 있습니다. 설계 상 C는 ​​C 자체 외부의 동작에 대해 많은 것을 보장하지 않습니다. 앱이 예기치 않게 종료되는 경우 런타임 라이브러리가 만든 약속은 더 이상 살아 있지 않기 때문에 무효가됩니다.
cHao

2

운영 체제는 일반적으로이를 정리하지만, 예를 들어 임베디드 소프트웨어를 작업하는 경우 릴리스되지 않을 수 있습니다.

비워두면 나중에 대규모 프로젝트에 통합 할 때 많은 시간을 절약 할 수 있습니다.


0

실제로 운영 체제에 따라 다르지만 접하게 될 모든 운영 체제에 대해 프로세스가 종료되면 메모리 할당이 사라집니다.


0

직접 해방이 가장 좋다고 생각합니다. 정의되지 않은 동작은 최악의 것이므로 프로세스에서 여전히 정의되어있는 동안 액세스 권한이있는 경우 수행하십시오. 사람들이 이에 대해 제공 한 많은 좋은 이유가 있습니다.

W98에서 실제 질문은 '언제'라는 것을 발견했습니다 (이를 강조하는 게시물을 보지 못했습니다). 작은 템플릿 프로그램 (다양한 malloc 공간을 사용하는 MIDI SysEx 입력 용)은 WndProc의 WM_DESTROY 비트에서 메모리를 비울 수 있지만 더 큰 프로그램에 이식하면 종료 할 때 충돌이 발생했습니다. 나는 이것이 큰 정리 중에 OS가 이미 해제 한 것을 해제하려고한다는 것을 의미한다고 생각했습니다. WM_CLOSE에서 한 다음 DestroyWindow ()를 호출하면 모두 정상적으로 작동하고 즉시 정리 종료됩니다.

이것은 MIDI 버퍼와 정확히 동일하지는 않지만 프로세스를 그대로 유지하고 완전히 정리 한 다음 종료하는 것이 가장 좋다는 점에서 유사성이 있습니다. 겸손한 메모리 청크를 사용하면 매우 빠릅니다. 많은 작은 버퍼가 적은 수의 큰 버퍼보다 ​​운영 및 정리에서 더 빠르게 작동한다는 것을 발견했습니다.

누군가가 디스크의 스왑 파일에서 대용량 메모리 청크를 되 돌리는 것을 피할 때 말했듯이 예외가있을 수 있지만, 할당 된 공간을 더 많이, 더 작게 유지함으로써 최소화 할 수 있습니다.

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