이것은 오랫동안 나를 귀찮게했던 것입니다.
우리는 모두 학교에서 (적어도 나는) 배운 모든 포인터를 자유롭게해야한다는 것을 배웁니다. 그래도 메모리를 해제하지 않는 실제 비용에 대해서는 약간 궁금합니다. malloc
루프 나 스레드 실행의 일부에서 호출 될 때와 같이 명백한 경우 에는 메모리 누수가 없도록 해제하는 것이 매우 중요합니다. 그러나 다음 두 가지 예를 고려하십시오.
먼저, 다음과 같은 코드가 있다면 :
int main()
{
char *a = malloc(1024);
/* Do some arbitrary stuff with 'a' (no alloc functions) */
return 0;
}
실제 결과는 무엇입니까? 내 생각은 프로세스가 죽고 힙 공간이 사라져서 호출을 놓칠 때 아무런 해가 없다는 것입니다 free
(그러나 어쨌든 폐쇄, 유지 보수성 및 모범 사례 를 위해 프로세스 를 갖는 것이 중요하다는 것을 알고 있습니다). 이 생각에 맞습니까?
둘째, 쉘처럼 작동하는 프로그램이 있다고 가정 해 봅시다. 사용자는 변수를 선언 할 수 있으며 aaa = 123
나중에 사용할 수 있도록 일부 동적 데이터 구조에 저장됩니다. 분명히 * alloc 함수 (해시 맵, 링크 된 목록 등)를 호출하는 솔루션을 사용하는 것이 분명합니다. 이러한 종류의 프로그램 malloc
의 경우 프로그램 실행 중에 이러한 변수가 항상 존재해야하며 정적 할당 공간으로이를 구현할 수있는 좋은 방법이 없기 때문에 호출 한 후에는 자유롭게 사용할 수 없습니다. 할당되었지만 프로세스 종료의 일부로 만 해제되는 많은 메모리를 갖는 것이 나쁜 설계입니까? 그렇다면 대안은 무엇입니까?
답변
거의 모든 최신 운영 체제는 프로그램이 종료 된 후 할당 된 모든 메모리 공간을 복구합니다. 내가 생각할 수있는 유일한 예외는 프로그램의 정적 저장소와 런타임 메모리가 거의 같은 팜 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 시간을 소모하여 디스크 페이징 작업, 캐시 누락 및 캐시 제거를 초래할 수 있습니다.
미래의 코드 재사용 가능성 에 관해서는 무의미한 작전 의 확실성 을 정당화합니다 . 고려 사항이지만 민첩한 방법 은 아닙니다 . 야 그니!
답변
나는 OP가 정확하거나 해가 없다고 말하는 모든 사람들에게 완전히 동의하지 않습니다.
모두가 현대 및 / 또는 레거시 OS에 대해 이야기하고 있습니다.
그러나 OS가없는 환경에 있다면 어떻게해야합니까? 아무것도없는 곳?
이제 스레드 스타일 인터럽트를 사용하고 메모리를 할당한다고 가정하십시오. C 표준 ISO / IEC : 9899에서 메모리 수명은 다음과 같습니다.
7.20.3 메모리 관리 기능
1 calloc, malloc 및 realloc 함수에 대한 연속 호출로 할당 된 스토리지 순서 및 연속성은 지정되지 않았습니다. 할당이 성공하면 반환 된 포인터는 모든 유형의 객체에 대한 포인터에 할당 된 다음 할당 된 공간에서 해당 객체 또는 이러한 객체의 배열에 액세스하는 데 사용될 수 있도록 적절히 정렬됩니다 (공간이 명시 적으로 할당 해제 될 때까지). . 할당 된 객체의 수명은 할당에서 할당 해제까지 연장됩니다. […]
따라서 환경이 당신을 위해 해방 일을하고 있다고 주어서는 안됩니다. 그렇지 않으면 마지막 문장에 “또는 프로그램이 종료 될 때까지”추가됩니다.
즉, 메모리를 비우는 것은 나쁜 습관이 아닙니다. 이식성이 없으며 C 준수 코드가 아닙니다. 적어도 ‘다음과 같은 경우 […], 환경에서 지원되는 경우’올바른 것으로 표시 될 수 있습니다.
그러나 OS가 전혀없는 경우 아무도 당신을 위해 일하고 있지 않습니다 (일반적으로 임베디드 시스템에서 메모리를 할당하고 재 할당하지 않지만 원하는 경우가 있습니다).
따라서 일반 C에서 (OP 태그가 붙은) 일반적으로 말하자면 잘못되고 이식성이없는 코드를 생성하는 것입니다.
답변
완료되면 모든 할당 된 블록을 해제합니다. 오늘 내 프로그램의 진입 점은 일 수 main(int argc, char *argv[])
있지만 내일은 foo_entry_point(char **args, struct foo *f)
함수 포인터로 입력 될 수 있습니다 .
그래서 그런 일이 생기면 이제 누수가 있습니다.
두 번째 질문과 관련하여 내 프로그램이 a = 5와 같은 입력을 받으면 a에 공간을 할당하거나 후속 a = “foo”에 동일한 공간을 다시 할당합니다. 이것은 다음까지 할당 된 상태로 유지됩니다.
- 사용자가 ‘unset a’를 입력했습니다
- 신호를 처리하거나 사용자가 ‘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 번 결정되지 않은 크기를 유출했습니다.
훌륭하고 잘 작성된 프로그램은 항상 자체적으로 정리해야합니다. 모든 메모리를 비우고, 모든 파일을 플러시하고, 모든 디스크립터를 닫고, 모든 임시 파일을 링크 해제하십시오. 충돌을 감지하고 다시 시작하십시오.
정말로, 당신이 다른 것들로 넘어갈 때 당신의 물건을 유지해야하는 가난한 영혼에게 친절하십시오.
답변
종료 할 때 메모리를 비워 두는 것이 좋습니다. malloc ()은 “힙”이라는 메모리 영역에서 메모리를 할당하며 프로세스가 종료되면 프로세스의 전체 힙이 해제됩니다.
즉, 사람들이 종료하기 전에 모든 것을 해제해야한다고 주장하는 한 가지 이유는 메모리 디버거 (예 : Linux의 valgrind)가 해제되지 않은 블록을 메모리 누수로 감지하고 “실제”메모리 누수가있는 경우 마지막에 “가짜”결과를 얻는다면 더 쉽게 찾을 수 없습니다.
