malloc 후에 해방되지 않으면 어떻게 되나요?


538

이것은 오랫동안 나를 귀찮게했던 것입니다.

우리는 모두 학교에서 (적어도 나는) 배운 모든 포인터를 자유롭게해야한다는 것을 배웁니다. 그래도 메모리를 해제하지 않는 실제 비용에 대해서는 약간 궁금합니다. malloc루프 나 스레드 실행의 일부에서 호출 될 때와 같이 명백한 경우 에는 메모리 누수가 없도록 해제하는 것이 매우 중요합니다. 그러나 다음 두 가지 예를 고려하십시오.

먼저, 다음과 같은 코드가 있다면 :

int main()
{
    char *a = malloc(1024);
    /* Do some arbitrary stuff with 'a' (no alloc functions) */
    return 0;
}

실제 결과는 무엇입니까? 내 생각은 프로세스가 죽고 힙 공간이 사라져서 호출을 놓칠 때 아무런 해가 없다는 것입니다 free(그러나 어쨌든 폐쇄, 유지 보수성 및 모범 사례 를 위해 프로세스 를 갖는 것이 중요하다는 것을 알고 있습니다). 이 생각에 맞습니까?

둘째, 쉘처럼 작동하는 프로그램이 있다고 가정 해 봅시다. 사용자는 변수를 선언 할 수 있으며 aaa = 123나중에 사용할 수 있도록 일부 동적 데이터 구조에 저장됩니다. 분명히 * alloc 함수 (해시 맵, 링크 된 목록 등)를 호출하는 솔루션을 사용하는 것이 분명합니다. 이러한 종류의 프로그램 malloc의 경우 프로그램 실행 중에 이러한 변수가 항상 존재해야하며 정적 할당 공간으로이를 구현할 수있는 좋은 방법이 없기 때문에 호출 한 후에는 자유롭게 사용할 수 없습니다. 할당되었지만 프로세스 종료의 일부로 만 해제되는 많은 메모리를 갖는 것이 나쁜 설계입니까? 그렇다면 대안은 무엇입니까?


7
@NTDLS 등급 시스템의 마술은 실제로 한 번만 유효합니다. 6 년 동안 "더 가치있는"답변이 실제로 최고로 올랐습니다.
zxq9 2019

15
아래 사람들은 좋은 최신 OS는 정리하지만 코드가 커널 모드에서 실행되는 경우 (예를 들어 성능상의 이유로) 어떻게 말하는가? 커널 모드 프로그램 (예 : Linux)은 샌드 박스로되어 있습니까? 그렇지 않다면 abort ()와 같은 비정상적인 종료 전에도 수동으로 모든 것을 해제해야한다고 생각합니다.
Dr. Person Person II

3
@ Dr.PersonPersonII 예, 커널 모드에서 실행되는 코드는 일반적으로 모든 것을 수동으로 해제해야합니다.
zwol

1
free(a)실제로 메모리를 확보하기 위해 아무것도하지 않는 것을 추가하고 싶습니다 ! malloc의 libc 구현에서 일부 포인터를 재설정하여 큰 mmapped 메모리 페이지 (일반적으로 "힙"이라고 함) 내에서 사용 가능한 메모리 청크를 추적합니다. 이 페이지는 여전히 이전이 아니라 프로그램이 종료 될 때만 해제됩니다.
마르코 Bonelli

1
Free ()는 실제로 메모리를 해제하거나 해제하지 않을 수 있습니다. 블록을 해제 된 상태로 표시하거나 나중에 교정하거나 사용 가능한 목록에 링크 할 수 있습니다. 인접한 빈 블록으로 병합하거나 후속 할당을 위해 남겨 둘 수 있습니다. 모두 구현 세부 사항입니다.
Jordan Brown

답변:


378

거의 모든 최신 운영 체제는 프로그램이 종료 된 후 할당 된 모든 메모리 공간을 복구합니다. 내가 생각할 수있는 유일한 예외는 프로그램의 정적 저장소와 런타임 메모리가 거의 같은 팜 OS와 같은 것일 수 있으므로 해제하지 않으면 프로그램이 더 많은 저장소를 차지할 수 있습니다. (나는 여기서 추측하고 있습니다.)

따라서 일반적으로 필요한 것보다 많은 스토리지를 갖는 런타임 비용을 제외하고는 아무런 해가 없습니다. 확실히 당신이 제공 한 예에서, 당신은 지워질 때까지 사용될 수있는 변수에 대한 메모리를 유지하려고합니다.

그러나 더 이상 필요하지 않은 즉시 메모리를 비우고 프로그램 종료시 남아있는 모든 것을 비우는 것이 좋은 스타일로 간주됩니다. 사용중인 메모리를 파악하고 여전히 필요한지 여부를 생각하는 데 더 많은 연습이 필요합니다. 추적하지 않으면 메모리 누수가있을 수 있습니다.

반면에 종료시 파일을 닫으라는 비슷한 훈계는 훨씬 더 구체적인 결과를 낳습니다. 그렇지 않으면 파일에 기록한 데이터가 플러시되지 않거나 임시 파일 인 경우에는 그렇지 않을 수 있습니다 완료되면 삭제됩니다. 또한 데이터베이스 핸들은 트랜잭션을 커밋 한 다음 완료되면 닫아야합니다. 마찬가지로 C ++ 또는 Objective C와 같은 객체 지향 언어를 사용하는 경우 객체를 완료했을 때 객체를 해제하지 않으면 소멸자가 절대 호출되지 않으며 클래스가 담당하는 모든 리소스가 정리되지 않을 수 있습니다.


16
누군가가 귀하의 프로그램을 가져 와서 (메모리를 복구하지 않는 OS에서 계속 실행하는 경우) GG를 실행하면 모든 사람이 최신 운영 체제를 사용하고 있지 않다는 것도 언급하는 것이 좋습니다.
user105033

79
나는이 답변이 잘못되었다고 생각합니다. 파일 처리 / 메모리 / 뮤텍스와 같이 자원을 처리 한 후에는 항상 자원을 할당 해제해야합니다. 그러한 습관을 가짐으로써 서버를 구축 할 때 그런 실수를하지 않을 것입니다. 일부 서버는 연중 무휴로 운영 될 것으로 예상됩니다. 이러한 경우 모든 종류의 누출은 서버에 결국 해당 리소스가 부족하여 어떤 식 으로든 중단 / 충돌됨을 의미합니다. 짧은 유틸리티 프로그램, 나중에 누출은 그렇게 나쁘지 않습니다. 모든 서버, 누출은 모두 사망입니다. 호의를 베푸십시오. 자신을 정리하십시오. 좋은 습관입니다.
EvilTeach

120
"그러나 더 이상 필요하지 않은 즉시 메모리를 비우고 프로그램 종료시 남아있는 모든 것을 비우는 것이 좋은 스타일로 간주됩니다." 그렇다면 잘못 생각하십니까?
Paul Tomblin

24
프로그램이 종료 될 때까지 바로 필요한 메모리 저장소가 있고 기본 OS에서 실행 중이 아닌 경우 종료 직전에 메모리를 해제하는 것이 결함이 아닌 문체 선택입니다.
Paul Tomblin

30
@Paul-EvilTeach에 동의하는 것은 메모리를 확보하는 데 좋은 스타일로 간주되지 않습니다. 메모리를 확보하지 않는 것은 올바르지 않습니다. 당신의 말은 이것이 넥타이와 일치하는 손수건을 착용하는 것만 큼 중요하게 보입니다. 실제로 바지를 입는 정도입니다.
Heath Hunnicutt

110

예, 그렇습니다. 귀하의 모범은 해를 끼치 지 않습니다 (적어도 최신 운영 체제에서는 아닙니다). 프로세스에서 할당 한 모든 메모리는 프로세스가 종료되면 운영 체제에서 복구합니다.

출처 : 할당 및 GC 신화 (PostScript alert!)

할당 신화 4 : 가비지 수집되지 않은 프로그램은 항상 할당 된 모든 메모리를 할당 해제해야합니다.

진실 : 자주 실행되는 코드에서 생략 된 할당 해제는 누출을 증가시킵니다. 그들은 거의 받아 들일 수 없습니다. 그러나 프로그램이 종료 될 때까지 할당 된 메모리를 가장 많이 유지하는 프로그램은 종종 개입 해제없이 더 잘 수행됩니다. Malloc은 무료가 없다면 구현하기가 훨씬 쉽습니다.

대부분의 경우 프로그램 종료 직전에 메모리 할당 해제는 의미가 없습니다. OS는 어쨌든 그것을 되 찾을 것입니다. 자유의지는 만져지고 사물을 페이징합니다. OS는 그렇지 않습니다.

결과 : 할당을 계산하는 "누설 감지기"에주의하십시오. 일부 "누수"가 좋습니다!

즉, 모든 메모리 누수를 피해야합니다!

두 번째 질문 : 디자인이 좋습니다. 응용 프로그램이 종료 될 때까지 무언가를 저장 해야하는 경우 동적 메모리 할당 으로이 작업을 수행해도됩니다. 필요한 크기를 미리 모른다면 정적으로 할당 된 메모리를 사용할 수 없습니다.


3
내가 읽은 질문은이 특정 예제가 괜찮은지 여부가 아니라 유출 된 메모리에 실제로 발생하는 것이기 때문일 수 있습니다. 그래도 좋은 답변이므로 투표하지 않습니다.
DevinB

3
아마도 초기 Windows, 초기 Mac OS 등이 있었으며 아마도 종료하기 전에 메모리를 확보 해야하는 프로세스가 필요한 OS가있을 수 있습니다. 그렇지 않으면 공간이 회수되지 않습니다.
Pete Kirkham

메모리 조각화 또는 메모리 부족에 신경 쓰지 않는 한 완벽하게 괜찮습니다. 너무 많이하면 응용 프로그램 성능이 사라집니다. 어려운 사실 외에도 항상 모범 사례와 좋은 습관 형성을 따르십시오.
NTDLS

1
나는 현재 약 -11에 대한 대답을 받아 들였으므로 그는 기록을 세우기조차하지 않았습니다.
Paul Tomblin

8
"누설 감지기 때문에"라고 말하여 메모리를 free () 할 필요성을 설명하는 것은 잘못이라고 생각합니다. "경찰들이 스피드 카메라로 당신을 기다릴 수 있기 때문에 놀이 거리에서 천천히 운전해야한다"고 말하는 것과 같습니다.
Sebastian Mach

57

=== 향후 교정코드 재사용은 어떻습니까? ===

당신이 경우 하지 않는 개체를 무료로 코드를 작성하면 폐쇄 프로세스에 의해 free되기를되는 메모리에 ... 즉 작은 일회용 의존 할 때, 당신은 안전 인에 코드를 제한하는 것은 사용하기 프로젝트 또는 "throw-away" [1] 프로젝트) ... 프로세스가 언제 종료되는지 알 수 있습니다.

당신이 경우에 () 모든 동적으로 할당 된 메모리를 무료입니다, 당신은 미래 코드를 교정하고시키는 것을 코드를 작성 다른 큰 프로젝트에서 그것을 사용할 수 있습니다.


[1] "throw-away"프로젝트에 관한 것. "Throw-away"프로젝트에 사용 된 코드는 버려지지 않습니다. 다음으로 10 년이 지났고 "throw-away"코드가 계속 사용되고 있습니다.

하드웨어가 더 잘 작동하도록 재미있게 코드를 작성한 사람에 대한 이야기를 들었습니다. 그는 " 단지 취미는 크고 전문적이지 않다 "고 말했다. 몇 년 후 많은 사람들이 그의 "취미"코드를 사용하고 있습니다.


8
"작은 프로젝트"를 위해 하향 투표. 대상 플랫폼을 아는 경우 시간 낭비이기 때문에 종료시 메모리를 확보 하지 않는 대규모 프로젝트가 많이 있습니다. 보다 정확한 예인 IMO는 "절연 된 프로젝트"였습니다. 예를 들어, 다른 응용 프로그램에 포함될 재사용 가능한 라이브러리를 만드는 경우, 잘 정의 된 종료 지점이 없으므로 메모리가 누출되지 않아야합니다. 독립형 응용 프로그램의 경우 프로세스가 종료되는 시점을 항상 정확히 알 수 있으며 OS로 정리를 오프로드하기 위해 의식적인 결정을 내릴 수 있습니다 (확인은 어느 쪽이든 수행해야 함).
Dan Bechard

어제의 응용 프로그램은 오늘날의 라이브러리 기능이며 내일은 수천 번 호출되는 오래 지속되는 서버에 연결됩니다.
Adrian McCarthy

1
@AdrianMcCarthy : 함수가 정적 포인터가 널인지 여부를 확인하고, 포인터가있는 malloc()경우이를 초기화하고 , 포인터가 여전히 널인 경우 종료되면 이러한 함수는 free호출되지 않더라도 임의의 횟수만큼 안전하게 사용될 수 있습니다 . 무한한 양의 스토리지를 사용할 수있는 메모리 누수와 유한하고 예측 가능한 스토리지 양만 낭비하는 상황을 구별하는 것이 가치가 있다고 생각합니다.
supercat

@ supercat : 내 의견은 시간이 지남에 따라 코드 변경에 대해 이야기하고있었습니다. 물론, 제한된 양의 메모리가 누출되는 것은 문제가되지 않습니다. 그러나 언젠가 누군가는 더 이상 정적 포인터를 사용하지 않도록 해당 기능을 변경하려고 할 것입니다. 코드에 지정된 메모리를 해제 할 수있는 준비가되어 있지 않으면 어려운 변경이 될 것입니다 (또는 더 나쁜 경우 변경이 나 빠지고 무한한 누출이 발생할 수 있습니다).
Adrian McCarthy

1
@AdrianMcCarthy : 더 이상 정적 포인터를 사용하지 않도록 코드를 변경하면 포인터를 일종의 "컨텍스트"개체로 이동하고 이러한 개체를 만들고 삭제하기위한 코드를 추가해야합니다. null할당이 존재하지 않을 때 포인터가 항상 존재하고 할당이 존재할 때 널이 아닌 경우, 코드를 사용하여 할당을 null해제하고 컨텍스트가 파괴 될 때 포인터를 설정하는 것은 특히 수행해야 할 다른 모든 것에 비해 간단합니다. 정적 객체를 컨텍스트 구조로 이동합니다.
supercat

52

당신은 정확하고 해를 끼치 지 않으며 종료하는 것이 더 빠릅니다.

이에 대한 여러 가지 이유가 있습니다.

  • 모든 데스크탑 및 서버 환경은 exit ()에서 전체 메모리 공간을 해제합니다. 힙과 같은 프로그램 내부 데이터 구조를 인식하지 못합니다.

  • 거의 모든 free()구현 메모리를 운영 체제에 반환 하지 않습니다 .

  • 더 중요한 것은 exit () 직전에 수행하면 시간 낭비입니다. 종료시 메모리 페이지와 스왑 공간이 해제됩니다. 반대로 일련의 free () 호출은 CPU 시간을 소모하여 디스크 페이징 작업, 캐시 누락 및 캐시 제거를 초래할 수 있습니다.

미래의 코드 재사용 가능성 에 관해서는 무의미한 작전 의 확실성 을 정당화합니다 . 고려 사항이지만 민첩한 방법 은 아닙니다 . 야 그니!


2
한 번은 프로그램 메모리 사용을 이해하는 데 짧은 시간을 소비 한 프로젝트에서 일했습니다 (우리는 그것을 지원해야했지만 작성하지 않았습니다). 경험을 바탕으로 나는 당신의 두 번째 총알에 일화 적으로 동의합니다. 그러나 나는 당신 (또는 누군가)이 이것이 사실이라는 더 많은 증거를 제공하고 싶습니다.
user106740 2009

3
결코 마음, 답을 발견 stackoverflow.com/questions/1421491/...를 . 매우 고맙습니다!
user106740 2009

YAGNI라는 @aviggiano.
v.oddou

YAGNI 원칙은 두 가지 방식으로 작동합니다. 종료 경로를 최적화 할 필요는 없습니다. 조기 최적화 및 그 모든 것.
Adrian McCarthy

26

나는 OP가 정확하거나 해가 없다고 말하는 모든 사람들에게 완전히 동의하지 않습니다.

모두가 현대 및 / 또는 레거시 OS에 대해 이야기하고 있습니다.

그러나 OS가없는 환경에 있다면 어떻게해야합니까? 아무것도없는 곳?

이제 스레드 스타일 인터럽트를 사용하고 메모리를 할당한다고 가정하십시오. C 표준 ISO / IEC : 9899에서 메모리 수명은 다음과 같습니다.

7.20.3 메모리 관리 기능

1 calloc, malloc 및 realloc 함수에 대한 연속 호출로 할당 된 스토리지 순서 및 연속성은 지정되지 않았습니다. 할당이 성공하면 반환 된 포인터는 모든 유형의 객체에 대한 포인터에 할당 된 다음 할당 된 공간에서 해당 객체 또는 이러한 객체의 배열에 액세스하는 데 사용될 수 있도록 적절히 정렬됩니다 (공간이 명시 적으로 할당 해제 될 때까지). . 할당 된 객체의 수명은 할당에서 할당 해제까지 연장됩니다. [...]

따라서 환경이 당신을 위해 해방 일을하고 있다고 주어서는 안됩니다. 그렇지 않으면 마지막 문장에 "또는 프로그램이 종료 될 때까지"추가됩니다.

즉, 메모리를 비우는 것은 나쁜 습관이 아닙니다. 이식성이 없으며 C 준수 코드가 아닙니다. 적어도 '다음과 같은 경우 [...], 환경에서 지원되는 경우'올바른 것으로 표시 될 수 있습니다.

그러나 OS가 전혀없는 경우 아무도 당신을 위해 일하고 있지 않습니다 (일반적으로 임베디드 시스템에서 메모리를 할당하고 재 할당하지 않지만 원하는 경우가 있습니다).

따라서 일반 C에서 (OP 태그가 붙은) 일반적으로 말하자면 잘못되고 이식성이없는 코드를 생성하는 것입니다.


4
반박 론은 만약 당신이 임베디드 환경이라면, 개발자로서 당신은 처음부터 메모리 관리에 훨씬 더 까다로울 것이라는 점입니다. 일반적으로 이것은 런타임 malloc / realloc을 전혀 사용하지 않고 실제로 정적 고정 메모리를 사전에 미리 할당하는 시점입니다.
John Go-Soco

1
@ Lunarplasma : 당신이 말하는 것은 틀린 것이 아니지만, 언어 표준이 무엇을 말하고 있는지에 대한 사실을 바꾸지 않으며, 그것에 대해 행동하거나 더 나아가는 사람은 상식적으로도 제한된 코드를 생성하고 있습니다. 괜찮은 경우가 많기 때문에 "내가 신경 쓰지 않아도된다"고 말하는 사람이있을 수 있습니다. 그러나 적어도 왜 그가 신경 쓸 필요가 없는지 알아야합니다. 질문이 특별한 경우와 관련이없는 한 특히 생략하지 마십시오. 그리고 OP는 이론적 인 (학교) 측면에서 일반적으로 C에 대해 묻기 때문에. "필요하지 않다"고 말하는 것은 좋지 않습니다!
dhein

2
OS가없는 대부분의 환경에서는 프로그램을 "종료"할 수있는 방법이 없습니다.
supercat

@ supercat : 내가 전에 쓴 것처럼 : 당신은 그것에 대해 맞습니다. 그러나 누군가 이유와 학교 측면을 가르치는 것과 관련하여 누군가가 그것에 대해 묻는다면, "당신은 그것이 중요하지 않은 대부분의 시간 동안 그것에 대해 생각할 필요가 없다"고 말하는 것은 옳지 않습니다. 정의는 이유 때문에 주어지며, 대부분의 환경에서 처리하기 때문에 신경 쓸 필요가 없다고 말할 수 없습니다. 그게 내 요점입니다.
dhein

2
메모리 관리 및 표준 라이브러리 기능과 관련하여 표준 명령 기능을 제공 할 런타임이 없기 때문에 운영 체제가없는 경우 C 표준을 인용하는 경우 -1로 인용합니다. 런타임 / OS와 함께).

23

완료되면 모든 할당 된 블록을 해제합니다. 오늘 내 프로그램의 진입 점은 일 수 main(int argc, char *argv[])있지만 내일은 foo_entry_point(char **args, struct foo *f)함수 포인터로 입력 될 수 있습니다 .

그래서 그런 일이 생기면 이제 누수가 있습니다.

두 번째 질문과 관련하여 내 프로그램이 a = 5와 같은 입력을 받으면 a에 공간을 할당하거나 후속 a = "foo"에 동일한 공간을 다시 할당합니다. 이것은 다음까지 할당 된 상태로 유지됩니다.

  1. 사용자가 'unset a'를 입력했습니다
  2. 신호를 처리하거나 사용자가 'quit'을 입력하여 정리 기능을 입력했습니다.

프로세스가 끝난 후에 메모리를 회수하지 않는 최신 OS는 생각할 수 없습니다 . 그런 다음 다시 free ()가 저렴합니다. 왜 정리하지 않습니까? 다른 사람들이 말했듯이, valgrind와 같은 도구는 실제로 걱정해야 할 누출을 발견하는 데 좋습니다. 예를 들어 블록이 '여전히 도달 가능'으로 표시되어 있지만 누출이 없도록 할 때 출력에 추가 노이즈가 발생합니다.

또 다른 신화는 " main ()에 있으면 해제 할 필요가 없다 "는 것입니다. 다음을 고려하세요:

char *t;

for (i=0; i < 255; i++) {
    t = strdup(foo->name);
    let_strtok_eat_away_at(t);
}

그것이 포크 / 데몬 이전 (이론은 영원히 실행되는) 이전에 온다면, 프로그램은 t 255 번 결정되지 않은 크기를 유출했습니다.

훌륭하고 잘 작성된 프로그램은 항상 자체적으로 정리해야합니다. 모든 메모리를 비우고, 모든 파일을 플러시하고, 모든 디스크립터를 닫고, 모든 임시 파일을 링크 해제하십시오. 충돌을 감지하고 다시 시작하십시오.

정말로, 당신이 다른 것들로 넘어갈 때 당신의 물건을 유지해야하는 가난한 영혼에게 친절하십시오.


1
그렇습니다. 팀원에게 "main ()에서 free ()를 호출 할 필요가 없습니다"라고 말한 적이 있습니다. <shudders>
Tim Post

free() is cheap복잡한 관계를 가진 수십억 개의 데이터 구조가 하나씩 해제되지 않는 한, 데이터 구조를 순회하여 모든 것을 해제하려고하면 특히 데이터 구조의 절반이 이미 페이지 아웃 된 경우 종료 시간이 크게 증가 할 수 있습니다 아무런 이점없이 디스크에.
Lie Ryan

3
당신이 같은 억 경우 @LieRyan은 그대로 :)이 특정 답변의 범위를 벗어나는 방법 - 억 구조를, 당신은 가장 확실히 고려의 전문 학위를 필요로 다른 문제가 발생
팀 포스트

13

종료 할 때 메모리를 비워 두는 것이 좋습니다. malloc ()은 "힙"이라는 메모리 영역에서 메모리를 할당하며 프로세스가 종료되면 프로세스의 전체 힙이 해제됩니다.

즉, 사람들이 종료하기 전에 모든 것을 해제해야한다고 주장하는 한 가지 이유는 메모리 디버거 (예 : Linux의 valgrind)가 해제되지 않은 블록을 메모리 누수로 감지하고 "실제"메모리 누수가있는 경우 마지막에 "가짜"결과를 얻는다면 더 쉽게 찾을 수 없습니다.


1
Valgrind는 "누설 된"과 "여전히 도달 할 수있는"을 구별하는 일을 잘하지 않습니까?
Christoffer

11
"완전히 좋은"-1 할당 된 메모리를 해제하지 않고 그대로 두는 것은 나쁜 코딩 관행입니다. 해당 코드를 라이브러리로 추출하면 모든 곳에서 메모리가 유출 될 수 있습니다.
DevinB

5
보상 +1 compie의 답변을 참조하십시오. free에서 exit시간 유해한 것으로 간주.
R .. GitHub 중지 지원 얼음

11

할당 한 메모리를 사용하는 경우 아무 것도 잘못하지 않은 것입니다. 메모리를 해제하지 않고 나머지 프로그램에서 사용 가능하게하지 않고 메모리를 할당하는 함수 (메인 이외)를 작성할 때 문제가됩니다. 그런 다음 할당 된 메모리로 프로그램을 계속 실행하지만 사용 방법은 없습니다. 프로그램 및 기타 실행중인 프로그램 에 해당 메모리가 없습니다.

편집 : 다른 실행중인 프로그램에 해당 메모리가 없다고 말하는 것은 100 % 정확하지 않습니다. 운영 체제는 프로그램을 가상 메모리 ( </handwaving>) 로 교체하는 대신 항상 사용하도록 할 수 있습니다 . 그러나 요점은 프로그램이 사용하지 않는 메모리를 비우면 가상 메모리 스왑이 덜 필요하다는 것입니다.


11

이 코드는 일반적으로 정상적으로 작동하지만 코드 재사용 문제를 고려하십시오.

할당 된 메모리를 해제하지 않는 일부 코드 스 니펫을 작성했을 수 있으며 메모리가 자동으로 회수되는 방식으로 실행됩니다. 괜찮아 보인다.

그런 다음 누군가가 스 니펫을 초당 1,000 회 실행하는 방식으로 프로젝트에 복사합니다. 그 사람은 이제 그의 프로그램에서 엄청난 메모리 누수가 있습니다. 일반적으로 서버 응용 프로그램에는 치명적이지 않습니다.

코드 재사용은 기업에서 일반적입니다. 일반적으로 회사는 직원이 생산하는 모든 코드를 소유하며 모든 부서는 회사가 소유 한 모든 것을 재사용 할 수 있습니다. 따라서 "순진하게 보이는"코드를 작성하면 다른 사람에게 두통을 일으킬 수 있습니다. 해고 당할 수도 있습니다.


2
누군가가 스 니펫을 복사하는 것뿐만 아니라 특정 작업을 한 번 반복하여 수행하도록 작성된 프로그램의 가능성에 주목할 가치가 있습니다. 이 경우 메모리를 한 번 할당 다음 해제하지 않고 반복적으로 사용 하는 것이 좋을 것입니다 . 그러나 모든 작업에 대해 메모리를 할당 및 해제하면 (해제하지 않고) 비참 할 수 있습니다.
supercat

7

실제 결과는 무엇입니까?

프로그램이 메모리를 누출했습니다. OS에 따라 복구되었을 있습니다.

대부분의 최신 데스크톱 운영 체제 프로세스 종료시 누수 된 메모리를 복구하므로 다른 많은 답변에서 볼 수 있듯이 문제를 무시하는 것이 슬프게 일반적입니다.)

그러나 당신은 당신에 의존해서는 안 안전 기능에 의존하고 있으며, 프로그램 (또는 함수)이 동작하는 시스템에서 실행할 수 않습니다 "하드"메모리 누수에 결과를 다음 시간입니다.

커널 모드 또는 메모리 보호를 트레이드 오프로 사용하지 않는 빈티지 / 임베디드 운영 체제에서 실행 중일 수 있습니다. MMU는 다이 공간을 차지하고 메모리 보호에는 추가 CPU주기가 필요하며 프로그래머가 스스로 정리 해달라고 요청하는 것은 그리 많지 않습니다.

원하는 방식으로 메모리를 사용하고 재사용 할 수 있지만 종료하기 전에 모든 리소스를 할당 해제해야합니다.


5

실제로 OSTEP 온라인 교과서에는 운영 체제의 학부 과정에 대한 섹션이 있습니다 .

관련 섹션은 6 페이지 의 메모리 API 장 에서 "메모리를 비우는 방법"에서 설명합니다.

어떤 경우에는 free ()를 호출하지 않는 것이 합리적 일 수 있습니다. 예를 들어, 프로그램은 수명이 짧아 곧 종료됩니다. 이 경우 프로세스가 종료되면 OS는 할당 된 모든 페이지를 정리하므로 자체적으로 메모리 누수가 발생하지 않습니다. 이것은 확실히 "작동"하지만 (7 페이지의 제쳐보기 참조) 개발하는 것은 나쁜 습관 일 수 있으므로 그러한 전략을 선택하는 것에주의하십시오

이 발췌문은 가상 메모리의 개념을 소개하는 데 있습니다. 기본적으로이 책의이 시점에서 저자는 운영 체제의 목표 중 하나가 "메모리 가상화", 즉 모든 프로그램이 매우 큰 메모리 주소 공간에 액세스 할 수 있다고 믿도록하는 것이라고 설명합니다.

뒤에서 운영 체제는 사용자에게 표시되는 "가상 주소"를 실제 메모리를 가리키는 실제 주소로 변환합니다.

그러나 실제 메모리와 같은 리소스를 공유하려면 운영 체제에서 사용중인 프로세스를 추적해야합니다. 따라서 프로세스가 종료되면 프로세스의 메모리를 회수하여 다른 프로세스와 메모리를 재분배하고 공유 할 수 있도록 운영 체제의 기능 및 설계 목표 내에 있습니다.


편집 : 발췌 부분에서 언급 한 내용은 아래에 복사되어 있습니다.

ASIDE : 프로세스가 종료 된 후 메모리가 누출되지 않는 이유

수명이 짧은 프로그램을 작성할 때을 사용하여 공간을 할당 할 수 있습니다 malloc(). 프로그램이 실행되고 완료 될 예정입니다. free()종료하기 전에 여러 번 호출해야 합니까? 그렇지 않은 것은 잘못된 것 같지만 어떤 의미에서도 "메모리를 잃어 버리지"않을 것입니다. 그 이유는 간단합니다. 시스템에는 실제로 두 가지 수준의 메모리 관리가 있습니다. 메모리 관리의 첫 번째 수준은 운영 체제에서 메모리를 실행할 때 프로세스에 전달하고 프로세스가 종료 될 때 (또는 그렇지 않으면) 메모리를 다시 가져옵니다. 전화 할 때 관리의 두 번째 수준은 힙 내에서 예를 들어, 각 공정 내 malloc()free(). 전화를하지 않아도free()(따라서 힙에서 메모리 누수) 운영 체제는 프로그램 실행이 완료되면 프로세스의 모든 메모리 (코드, 스택 및 힙 관련 페이지 포함)를 회수합니다. 주소 공간의 힙 상태에 관계없이 프로세스가 종료되면 OS가 해당 페이지를 모두 다시 가져 와서 메모리를 비우지 않았음에도 불구하고 메모리가 손실되지 않도록합니다.

따라서 수명이 짧은 프로그램의 경우 메모리 누수로 인해 운영상의 문제가 발생하지 않는 경우가 많습니다 (빈약 한 형태로 간주 될 수 있음). 웹 서버 나 데이터베이스 관리 시스템과 같이 오래 실행되지 않는 서버를 작성하면 유출 된 메모리가 훨씬 더 큰 문제이므로 응용 프로그램의 메모리가 부족할 때 충돌이 발생합니다. 물론 메모리 누수는 하나의 특정 프로그램에서 운영 체제 자체보다 훨씬 더 큰 문제입니다. 커널 코드를 작성하는 사람들은 가장 힘든 일을합니다.

메모리 API 장의 7 페이지 중

운영 체제 : 3 개의 쉬운 조각
Remzi H. Arpaci-Dusseau 및 Andrea C. Arpaci-Dusseau Arpaci-Dusseau Books 2015 년 3 월 (버전 0.90)


4

변수를 해제 하지 않아도 실제로 위험 하지는 않지만 첫 번째 블록을 해제하지 않고 메모리 블록에 대한 포인터를 다른 메모리 블록에 할당하면 첫 번째 블록에 더 이상 액세스 할 수 없지만 여전히 공간을 차지합니다. 이를 메모리 누수라고하며, 정기적으로이 작업을 수행하면 프로세스가 점점 더 많은 메모리를 사용하기 시작하여 다른 프로세스에서 시스템 리소스를 제거합니다.

프로세스가 오래 지속되면 프로세스가 완료 될 때 운영 체제가 할당 된 모든 메모리를 회수하므로이 작업을 수행하지 않아도되는 경우가 많지만 더 이상 사용하지 않는 모든 메모리를 비우는 습관을들이는 것이 좋습니다.


1
나는 당신이 첫 번째 문장 "위험이 없다"에 -1을 말하고 왜 위험이 있는지에 대해 신중한 대답을합니다.
DevinB

2
위험이 가해지면 그것은 매우 양성입니다-나는 segfault를 통해 언젠가는 메모리 누수를 취할 것입니다.
Kyle Cronin 2016 년

1
매우 사실이며, 우리 둘 다 = D를 선호하지 않을 것입니다.
DevinB

2
@KyleCronin 나는 것 많이 모두 심각한 버그와 세그먼테이션 폴트 (segfault)를 감지하기가 더 쉽습니다 때문이 아니라, 메모리 누수보다 세그먼트 폴트가 있습니다. 너무 자주 메모리 누수는 "꽤 양성"이기 때문에 눈에 띄지 않거나 해결되지 않습니다. 내 RAM과 나는 전적으로 동의하지 않습니다.
Dan Bechard

@Dan 개발자로서 확실합니다. 사용자로서 메모리 누수가 발생합니다. 오히려 메모리 누수가 있지만 작동하지 않는 소프트웨어보다 작동하는 소프트웨어를 원합니다.
Kyle Cronin

3

그 점에서 당신은 절대적으로 정확합니다. 프로그램이 종료 될 때까지 변수가 존재해야하는 작은 사소한 프로그램에서는 메모리 할당을 해제하면 실질적인 이점이 없습니다.

사실, 나는 프로그램의 각 실행이 매우 복잡하지만 상대적으로 수명이 짧은 프로젝트에 한 번 참여했으며 메모리 할당을 유지하고 실수를 할당 취소하여 프로젝트를 불안정하게하지 않기로 결정했습니다.

즉, 대부분의 프로그램에서 이것은 실제로 옵션이 아니며 메모리 부족으로 이어질 수 있습니다.


2

프로세스가 종료되면 메모리가 자동으로 해제됩니다. 일부 사람들은 프로세스가 종료 될 때 광범위한 정리를하지 않기 위해 노력합니다. 프로세스가 모두 운영 체제에 양도되기 때문입니다. 그러나 프로그램이 실행되는 동안 사용하지 않는 메모리를 비워야합니다. 그렇지 않으면 작업 세트가 너무 커지면 결국 부족하거나 과도한 페이징을 유발할 수 있습니다.


2

처음부터 응용 프로그램을 개발하는 경우 무료 통화 시간에 대한 교육 된 선택을 할 수 있습니다. 예제 프로그램은 괜찮습니다. 메모리를 할당하고 몇 초 동안 작동시킨 다음 닫아서 청구 한 모든 리소스를 해제합니다.

서버 / 오래 실행되는 응용 프로그램 또는 다른 사람이 사용할 라이브러리 인 다른 것을 작성하는 경우 malloc에 ​​대한 모든 것을 무료로 호출해야합니다.

실용적 측면을 잠시 무시하면 더 엄격한 접근 방식을 따르는 것이 훨씬 안전하고 malloc의 모든 것을 자유롭게 할 수 있습니다. 코딩 할 때마다 메모리 누수를보고 싶지 않다면 몇 가지 누수가 발생할 수 있습니다. 다시 말해, 예, 당신은 그것 없이도 도망 갈 수 있습니다. 그래도 조심하십시오.


0

프로그램이 종료되기 전에 몇 메가 바이트를 해제하는 것을 잊어 버린 경우 운영 체제에서 해제합니다. 그러나 프로그램이 한 번에 몇 주 동안 실행되고 프로그램 내부의 루프가 각 반복에서 몇 바이트를 비우는 것을 잊어 버린 경우 정기적으로 재부팅하지 않으면 컴퓨터에서 사용 가능한 모든 메모리를 소모하는 거대한 메모리 누수가 발생합니다. 기초 => 프로그램이 원래 설계된 것이 아니더라도 아주 큰 작업에 프로그램을 사용하면 작은 메모리 누수도 나빠질 수 있습니다.


-2

두 예제는 실제로 하나 free()의 프로세스 라고 생각합니다 . 프로세스가 끝날 때만 발생해야합니다. 프로세스가 종료되었으므로 쓸모가 없습니다.

그러나 두 번째 예에서 유일한 차이점은 정의되지 않은 수의을 허용하여 malloc()메모리가 부족해질 수 있다는 것입니다. 상황을 처리하는 유일한 방법은 리턴 코드를 확인 malloc()하고 그에 따라 조치하는 것입니다.

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