Programing

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

lottogame 2020. 2. 12. 07:59
반응형

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


이것은 지금 오랫동안 나를 귀찮게 한 것입니다.

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

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

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

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

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


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

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

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

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


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

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

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

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

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

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

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

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


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

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

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


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

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


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

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

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

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

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

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


완료되면 모든 할당 된 블록을 해제합니다. 오늘 내 프로그램의 진입 점은 일 수 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 번 결정되지 않은 크기를 유출했습니다.

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

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


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

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

그러나 OS가없는 환경에 있다면 어떨까요? 아무것도없는 곳?

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

7.20.3 메모리 관리 기능

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

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

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

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

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


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

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


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

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


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

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

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

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


실제 결과는 무엇입니까?

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

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

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

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

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


실제로 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)


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

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


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

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

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


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


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

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

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


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


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

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

참고 URL : https://stackoverflow.com/questions/654754/what-really-happens-when-you-dont-free-after-malloc



반응형