메모리 누수는 얼마나 멀리 갈 수 있습니까?


118

메모리 누수가 여러 번 발생했습니다. 보통 내가 malloc내일이없는 것처럼, 또는 FILE *더러운 빨래처럼 매달릴 때 . 나는 일반적으로 적어도 프로그램이 종료 될 때 모든 메모리가 정리된다고 가정합니다 (필사적으로 희망합니다). 프로그램이 종료되거나 충돌 할 때 누수 된 메모리가 수집되지 않는 상황이 있습니까?

대답이 언어마다 크게 다르면 C (++)에 중점을 둡니다.

'내일이없는 것처럼', '매달려 ... 더러운 세탁물처럼'이라는 문구의 쌍곡선 사용에 유의하십시오. 안전하지 않은 * malloc* ing은 사랑하는 사람을 해칠 수 있습니다. 또한 세탁물이 더러워지면 조심해서 사용하십시오.


3
Linux 또는 Windows와 같은 "최신"OS로 실행하는 경우 프로그램이 종료 될 때 OS 자체가 출시되지 않은 메모리를 확인합니다.
Oliver Charlesworth 2013 년

60
내일이 없다고 생각하는 대신 내일이있는 척하고 기억을 추적하세요!
William Pursell

8
@WilliamPursell 아, 그래서 당신은 calloc내일이 없다는 것을 좋아 해야한다고 말하는 것입니다. 우수한.
DilithiumMatrix

8
"답이 언어마다 크게 다르면 c (++)에 집중하겠습니다." CC ++ 는 같은 언어가 아닙니다!
Johnsyweb

11
@zhermes : C와 C ++가 다른 언어라는 것에 대한 의견은 생각보다 더 숨 깁니다 ... C ++에서는 자동 저장 기간이있는 개체를 활용하고 RAII 관용구를 따르고 ...이 개체가 메모리를 처리하도록합니다. 당신을위한 관리.
LihO 2013 년

답변:


111

아니요. 운영 체제는 프로세스가 종료 될 때 보유한 모든 리소스를 해제합니다.

이것은 운영 체제가 유지하는 모든 리소스에 적용됩니다 : 메모리, 열린 파일, 네트워크 연결, 창 핸들 ...

즉, 프로그램이 운영 체제가없는 임베디드 시스템에서 실행되거나 매우 단순하거나 버그가있는 운영 체제가있는 경우 재부팅 할 때까지 메모리를 사용하지 못할 수 있습니다. 그러나 그 상황에 있었다면 아마도이 질문을하지 않을 것입니다.

운영 체제에서 특정 리소스를 해제하는 데 시간이 오래 걸릴 수 있습니다. 예를 들어, 네트워크 서버가 연결을 수락하는 데 사용하는 TCP 포트는 프로그램에 의해 제대로 닫혀 있어도 몇 분이 걸릴 수 있습니다. 네트워크 프로그램은 데이터베이스 개체와 같은 원격 리소스를 보유 할 수도 있습니다. 원격 시스템은 네트워크 연결이 끊어지면 해당 리소스를 해제해야하지만 로컬 운영 체제보다 더 오래 걸릴 수 있습니다.


5
RTOS의 일반적인 패러다임은 단일 프로세스, 다중 스레드 모델이며 '작업'간에 메모리 보호가 없습니다. 일반적으로 하나의 힙이 있습니다. 이것은 확실히 VxWorks가 작동했던 방식이며 아마도 여전히 작동합니다.
marko

29
운영 체제에서 모든 리소스를 해제 할 수있는 것은 아닙니다. 네트워크 연결, 데이터베이스 트랜잭션 등을 명시 적으로 닫지 않으면 원하지 않는 결과가 발생할 수 있습니다. 네트워크 연결을 닫지 않으면 서버가 사용자가 무기한 활성 상태라고 생각할 수 있으며 활성 연결 수를 제한하는 서버의 경우 실수로 서비스 거부가 발생할 수 있습니다. 데이터베이스 트랜잭션을 닫지 않으면 커밋되지 않은 데이터가 손실 될 수 있습니다.
Lie Ryan

1
@Marko : vxWorks 최신 버전은 이제 메모리 보호를 지원하는 RTP (실시간 프로세스)를 지원합니다.
Xavier T.

20
"운영 체제는 프로세스가 종료 될 때 보유한 모든 리소스를 해제합니다." 엄격히 사실이 아닙니다. 예를 들어, (적어도) Linux에서 SysV 세마포어 및 기타 IPC 개체는 프로세스 종료시 정리되지 않습니다. 그래서 ipcrm수동 정리를위한 linux.die.net/man/8/ipcrm이 있습니다.
sleske 2013 년

7
객체가 유지하는 임시 파일이있는 경우 또한, 그것은 분명 나중에 정리되지 않습니다.
Mooing Duck 2013

47

C 표준은 malloc프로그램이 종료 될 때 할당 된 메모리 가 해제 되도록 지정하지 않습니다 . 이것은 운영 체제에 의해 수행되며 모든 OS (일반적으로 이들은 임베디드 세계에 있음)가 프로그램이 종료 될 때 메모리를 해제하지 않습니다.


20
즉 더 많거나 적은 때문에 C의 C 실행의 발생에 프로그램이 아닌 운영 체제 ...에 대한 C 표준 회담
vonbrand

5
@vonbrand C 표준은 main반환 할 때 할당 된 모든 메모리 malloc가 해제 된다는 단락을 가질 수 있습니다 . 예를 들어 열려있는 모든 파일은 프로그램 종료 전에 닫힙니다. my malloc에 할당 된 메모리의 경우 지정되지 않았습니다. 물론 OS에 관한 내 문장은 표준이 규정하는 것이 아니라 일반적으로 수행되는 것을 설명합니다.
ouah

내 의견을 수정하겠습니다. 표준은 프로그램 시작 및 중지 방법이 아니라 C에 대해 설명합니다. OS 없이 실행되는 C 프로그램을 아주 잘 작성할 수 있습니다 . 이 경우 정리할 사람이 없습니다. 이 표준은 매우 필요하지 않는 한 일부러 그렇게 할 필요없이하지 제한 용도로, 아무 것도 지정하지 않습니다.
vonbrand 2013 년

2
@ouah : " 메인이 반환 될 때 ...". 그것은 가정입니다. 우리는 " 만약 주요 수익률 ..." 을 고려해야 합니다. std::atexit또한를 통한 프로그램 종료를 고려한 std::exit다음 std::abort및 (C ++ 특정)도 std::terminate있습니다.
MSalters 2013 년

@ouah : 포함 된 경우 atexit사용할 수 없습니다. :-)
R .. GitHub의 STOP 돕기 ICE

28

모든 답변이 최신 OS에 대한 질문의 대부분의 측면을 다루었으므로 역사적으로 DOS 세계에서 프로그래밍 한 적이 있다면 언급 할 가치가있는 것이 있습니다. Terminant and Stay Resident (TSR) 프로그램은 일반적으로 시스템에 제어권을 반환하지만 소프트웨어 / 하드웨어 인터럽트에 의해 회복 될 수있는 메모리에 상주합니다. 이러한 OS에서 작업 할 때 "메모리 부족! 일부 TSR을 언로드 해보십시오" 와 같은 메시지가 나타나는 것은 정상이었습니다 .

따라서 기술적으로 프로그램은 종료 되지만 여전히 메모리에 있기 때문에 프로그램을 언로드하지 않으면 메모리 누수가 해제되지 않습니다.

따라서 버그가 있거나 임베디드 OS가 그렇게하도록 설계 되었기 때문에 메모리를 회수하지 않는 OS와는 다른 또 다른 경우라고 생각할 수 있습니다.

예를 하나 더 기억합니다. 주로 IBM 메인 프레임에서 실행되는 트랜잭션 서버 인 CICS ( Customer Information Control System )는 의사 대화 형입니다. 실행되면 사용자가 입력 한 데이터를 처리하고 사용자를위한 또 다른 데이터 세트를 생성하여 사용자 터미널 노드로 전송하고 종료합니다. 주의 키를 활성화하면 다시 활성화되어 다른 데이터 세트를 처리합니다. 작동 방식은 기술적으로 다시 말하지만 CICS 트랜잭션 서버를 재활용하지 않는 한 종료 된 CICS 프로그램에서 메모리를 회수하지 않습니다.


정말 흥미 롭습니다. 역사적 기록에 감사드립니다! 그 패러다임이 메모리를 확보하기 때문에 필요하지 않은 경우 계산 비용이 너무 많이 들기 때문인지 알고 있습니까? 아니면 대안이 아직 생각되지 않았습니까?
DilithiumMatrix 2013 년

1
@zhermes : DOS는 단순히 TSR에 대한 메모리 할당을 추적하지 않았기 때문에 계산적으로 불가능했습니다. 거의 정의상 : 목표는 상주유지 하는 것이 었습니다 . TSR이 모든 메모리가 아닌 일부를 비우도록하려면 무엇을 비 울지 결정하는 것은 사용자에게 달려 있습니다.
MSalters 2013 년

2
@zhermes : DOS (CP / M, 그 조상)는 현대적인 의미에서 운영 체제라고 부르는 것이 아닙니다. 한 번에 하나의 프로그램을 실행할 수있는 명령 프로세서와 함께 번들로 제공되는 표준 방식으로 호출 할 수있는 I / O 유틸리티 모음이었습니다. 프로세스에 대한 개념이 없었고 메모리는 가상도 보호되지도 않았습니다. TSR은 시스템이 최대 64K의 공간을 차지하고 있음을 알리고 인터럽트에 연결되어 호출을받을 수있는 유용한 해킹이었습니다.
Blrfl 2013 년

8

다른 사람들이 말했듯이 대부분의 운영 체제는 프로세스 종료시 할당 된 메모리를 회수합니다 (네트워크 소켓, 파일 핸들 등과 같은 기타 리소스).

그렇긴하지만 (원시 malloc / free 대신) new / delete를 처리 할 때 메모리 만 걱정할 필요가 없습니다. new에 할당 된 메모리는 회수 될 수 있지만 객체의 소멸자에서 수행 될 수있는 일은 발생하지 않습니다. 아마도 일부 클래스의 소멸자는 소멸시 센티넬 값을 파일에 씁니다. 프로세스가 막 종료되면 파일 핸들이 플러시되고 메모리가 회수 될 수 있지만 해당 센티넬 값은 기록되지 않습니다.

이야기의 도덕, 항상 자신을 정리하십시오. 물건을 매달리지 마십시오. 나중에 OS 정리에 의존하지 마십시오. 스스로 청소하십시오.


'후에 OS 정리에 의존하지 마십시오. 스스로 청소하십시오. ' 이것은 종종 복잡한 멀티 스레드 앱에서 '매우, 매우 어렵다'는 의미입니다. 리소스에 대한 모든 참조가 손실 된 실제 누출은 좋지 않습니다. 명시 적으로 참조를 해제하는 대신 OS가 정리할 수 있도록 허용하는 것이 항상 나쁜 것은 아니며 종종 취할 수있는 유일한 합리적인 방법입니다.
Martin James

1
C ++에서 소멸자는 것입니다 (일부보다 적게보다는 밝은하지 않는 프로그램의 종료에 호출되는 kill -9팬 쇼까지 ...)
vonbrand

@vonbrand 사실이지만 동적 객체의 누출에 대해 이야기하는 경우 이러한 소멸자가 발생하지 않습니다. 범위를 벗어난 개체는 원시 포인터이고 해당 소멸자는 작동하지 않습니다. (물론, ... RAII이 문제를 완화하기 위해 객체 참조)
안드레 Kostur에게

1
RAII의 문제는 실제로 제거하는 것이 중요하지 않은 프로세스 종료시 객체 할당 해제를 주장한다는 것입니다. 주의해야 할 DB 연결이지만 일반적인 메모리는 OS에서 정리하는 것이 가장 좋습니다 (훨씬 더 나은 작업 수행). 문제는 페이지 아웃 된 메모리 양이 증가하면 종료 하는 데 절대적으로 오래 걸리는 프로그램으로 나타 납니다. 그것은 ... 또한 해결하기 위해 비 사소한
DONAL 휄로우에게

@vonbrand : 그렇게 간단하지 않습니다. std::exitdtors를 호출 std::abort할 것입니다.
MSalters 2013 년

7

이것은 언어보다 운영 체제에 더 많이 의존합니다. 궁극적으로 모든 언어의 모든 프로그램은 운영 체제에서 메모리를 가져옵니다.

프로그램이 종료 / 충돌 할 때 메모리를 재활용하지 않는 운영 체제에 대해 들어 본 적이 없습니다. 따라서 프로그램이 할당해야하는 메모리에 상한선이있는 경우 할당하고 해제하지 않는 것이 완벽하게 합리적입니다.


단순한 OS의 경우 커널의 메모리 그림을 망칠 수 있습니까? .. 멀티 태스킹이없는 운영 체제처럼.
ulidtko 2013 년

@ulidtko, 이것은 일 망칠 것입니다. 내 프로그램이 가끔 1GiB를 요구하고 그 기간 동안 그것을 잡는다면, 그것을 사용하지 않는 동안에도 다른 사람들에게 그러한 자원의 사용을 거부하는 것입니다. 그것은 오늘날 중요 할 수도 있고 아닐 수도 있습니다. 그러나 환경 근본적으로 변할 입니다. 보장합니다.
vonbrand 2013 년

@vonbrand 1GiB를 드물게 사용하는 것은 (물리적 메모리가 충분한 한) 일반적으로 문제가되지 않습니다. 최신 운영 체제는 현재 활성화되지 않은 비트를 페이징 할 수 있기 때문입니다. 문제는 호스트 할 실제 메모리보다 활성 사용 중인 가상 메모리가 더 많을 때 발생 합니다.
Donal Fellows

5

프로그램이 다른 프로그램의 주소 공간에로드되는 동적 구성 요소 ( "플러그인")로 바뀌면 메모리 관리가 깔끔한 운영 체제에서도 문제가됩니다. 성능이 떨어지는 시스템으로 이식되는 코드에 대해 생각할 필요조차 없습니다.

반면에 모든 메모리를 해제 하면 프로그램 정리 성능에 영향을 미칠 수 있습니다 .

내가 작업하고 있던 한 프로그램은 프로그램이 종료되는 데 30 초 이상이 소요되는 특정 테스트 케이스입니다. 모든 동적 메모리의 그래프를 반복하여 하나씩 해제했기 때문입니다.

합리적인 해결책은 해당 기능을 가지고 테스트 케이스로 덮지 만 프로덕션 코드에서는 꺼서 애플리케이션이 빠르게 종료되는 것입니다.


5

제목에 해당하는 모든 운영 체제는 종료 후 프로세스가 엉망이 된 것을 정리합니다. 그러나 항상 예상치 못한 이벤트가 있습니다. 어떻게 든 액세스가 거부되고 일부 가난한 프로그래머가 가능성을 예견하지 못하여 나중에 다시 시도하지 않으면 어떻게됩니까? 메모리 누수가 미션 크리티컬 한 경우에는 항상 자신을 정리하는 것이 더 안전합니다. 그렇지 않으면 그 노력이 비용이 많이 든다면 IMO에 실제로 노력할 가치가 없습니다.

편집 : 루프와 같이 누적 될 위치에있는 경우 메모리 누수를 정리해야합니다. 내가 말한 메모리 누수는 프로그램 과정 내내 일정한 시간에 쌓이는 것입니다. 만약 당신이 다른 종류의 누수가 있다면 조만간 심각한 문제가 될 가능성이 높습니다.

기술적 인 측면에서 메모리 '복잡성'O (1)의 경우 대부분의 경우 괜찮습니다. O (logn)는 이미 불쾌하고 (경우에 따라 치명적) O (N) +는 견딜 수 없습니다.


3

POSIX 호환 시스템의 공유 메모리는 shm_unlink가 호출되거나 시스템이 재부팅 될 때까지 지속됩니다.


2

프로세스 간 통신이있는 경우 프로토콜에 따라 다른 프로세스가 완료되지 않고 리소스를 소비하지 않게 될 수 있습니다.

예를 들어, 저는 한때 프린터 작업 중에 JVM을 종료 할 때 Java에서 PDF 프린터로 인쇄하는 실험을하고 있었는데, PDF 스풀링 프로세스가 활성 상태로 남아 있었으며 작업 관리자에서이를 종료해야했습니다. 다시 인쇄 해보십시오.

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