C와 같은 언어에서는 프로그래머가 무료로 통화를 삽입해야합니다. 왜 컴파일러가 이것을 자동으로하지 않습니까? 인간은 합리적인 시간 (버그 무시)으로 처리하므로 불가능하지 않습니다.
편집 : 참고로, 여기에 흥미로운 예제가 다른 토론입니다.
C와 같은 언어에서는 프로그래머가 무료로 통화를 삽입해야합니다. 왜 컴파일러가 이것을 자동으로하지 않습니까? 인간은 합리적인 시간 (버그 무시)으로 처리하므로 불가능하지 않습니다.
편집 : 참고로, 여기에 흥미로운 예제가 다른 토론입니다.
답변:
프로그램이 메모리를 다시 사용할지 여부를 결정할 수 없기 때문입니다. 이것은 free()
모든 경우 에 호출 할 때 알고리즘을 정확하게 결정할 수 없다는 것을 의미합니다. 이는이 작업을 시도한 컴파일러가 메모리 누수가있는 일부 프로그램 및 / 또는 해제 된 메모리를 계속 사용하는 일부 프로그램을 생성해야 함을 의미합니다. 컴파일러가 두 번째 작업을 수행하지 않았고 프로그래머가 free()
버그를 수정하기 위해 호출을 삽입하도록 허용 free()
하더라도 해당 컴파일러 를 호출 하는 시간을 아는 free()
것은 시도하지 않은 컴파일러를 사용할 때 호출하는 시간을 아는 것보다 훨씬 어렵습니다. 도와주세요.
free()
올바르게 삽입하기를 기대 합니다.
David Richerby가 올바르게 지적했듯이 문제는 일반적으로 결정할 수 없습니다. 객체 라이브 니스는 프로그램의 글로벌 속성이며 일반적으로 프로그램의 입력에 따라 달라질 수 있습니다.
정확한 동적 가비지 수집 조차도 결정 불가능한 문제입니다! 모든 실제 가비지 수집기는 도달 가능성을 나중에 할당 된 개체가 필요한지 여부에 대한 보수적 인 근사값으로 사용합니다. 근사치이지만 근사치입니다.
그러나 그것은 일반적으로 사실입니다. 컴퓨터 과학 사업에서 가장 악명 높은 경찰 중 하나는 "일반적으로 불가능하기 때문에 우리는 아무것도 할 수 없습니다"입니다. 반대로, 진로를 만들 수있는 경우가 많이 있습니다.
참조 카운팅에 기반한 구현은 "컴파일러 삽입 해제"와 매우 유사하여 차이를 말하기가 어렵습니다. LLVM 의 자동 참조 카운팅 ( Objective-C 및 Swift에서 사용 )이 유명한 예입니다.
지역 유추 및 컴파일 타임 가비지 수집 은 현재 활발한 연구 분야입니다. ML 및 Mercury 와 같은 선언적 언어 에서는 객체를 만든 후에 수정할 수없는 훨씬 쉬운 것으로 판명되었습니다 .
이제 인간 주제에 대해 인간이 할당 수명을 수동으로 관리하는 세 가지 주요 방법이 있습니다.
할당 해제 문의 최적 배치가 결정 불가능하다는 것은 사실이지만 여기서는 문제가되지 않습니다. 사람과 컴파일러 모두에게 결정할 수 없기 때문에 수동 프로세스인지 자동 프로세스인지에 관계없이 항상 최적의 할당 해제 배치를 선택하는 것은 불가능합니다. 그리고 완벽한 사람은 아무도 없기 때문에, 충분히 진보 된 컴파일러는 인간이 대략 최적의 배치를 추측 할 때 성능을 능가 할 수 있어야합니다. 따라서 결정 불가능 성이 명시 적 할당 해제 문이 필요한 이유는 아닙니다 .
외부 지식이 할당 해제 명세서 배치를 알려주는 경우가 있습니다. 그런 다음 해당 명령문을 제거하는 것은 운영 로직의 일부를 제거하는 것과 동일하며 컴파일러에게 해당 로직을 자동으로 생성하도록 요청하는 것은 생각하는 것을 추측하도록 요청하는 것과 같습니다.
예를 들어, REPL (Read-Evaluate-Print-Loop)을 작성한다고 가정합니다 . 사용자가 명령을 입력하면 프로그램이이를 실행합니다. 사용자는 REPL에 명령을 입력하여 메모리를 할당 / 할당 할 수 있습니다. 소스 코드는 사용자가 명령을 입력 할 때 할당 해제를 포함하여 가능한 모든 사용자 명령에 대해 REPL이 수행 할 작업을 지정합니다.
그러나 C 소스 코드가 할당 취소를위한 명시 적 명령을 제공하지 않으면 컴파일러는 사용자가 REPL에 적절한 명령을 입력 할 때 할당 해제를 수행해야한다고 유추해야합니다. 이 명령이 "할당 해제", "무료"또는 다른 것입니까? 컴파일러는 원하는 명령을 알 수있는 방법이 없습니다. 해당 명령 단어를 찾기 위해 논리로 프로그래밍하고 REPL이 찾더라도 컴파일러는 소스 코드에서 명시 적으로 지시하지 않는 한 할당 취소로 명령에 응답해야한다는 것을 알 수 없습니다.
tl; dr 문제는 C 소스 코드가 컴파일러에 외부 지식을 제공하지 않는다는 것입니다. 프로세스가 수 동인지 자동인지 여부에 따라 결정 불가능 성이 문제가되지 않습니다.
현재 게시 된 답변 중 완전히 정확한 답변은 없습니다.
컴파일러가 할당 해제를 자동으로 삽입하지 않는 이유는 무엇입니까?
일부는 그렇습니다. (나중에 설명하겠습니다.)
사소하게, free()
프로그램이 종료되기 직전에 호출 할 수 있습니다 . 그러나 귀하의 질문 free()
에는 가능한 한 빨리 전화해야 할 필요가 있습니다.
free()
메모리에 도달 할 수없는 즉시 C 프로그램을 언제 호출 해야하는지에 대한 문제는 결정 불가능합니다. 이 문제와 임의의 다른 프로그램의 결정 불가능한 사항은 Halting Problem 에서 증명할 수 있습니다 .
결정 불가능한 문제는 컴파일러이든 인간이든 알고리즘에 의해 유한 한 시간 안에 항상 해결 될 수는 없습니다.
인간은 ( 그들 자신의) 알고리즘에 의해 메모리 정확성을 검증 할 수 있는 C 프로그램 의 서브셋 을 작성하려고한다 .
일부 언어는 # 5를 컴파일러에 빌드하여 # 1을 달성합니다. 메모리 할당을 임의로 사용하는 프로그램은 허용하지 않고 결정 가능한 하위 세트를 허용합니다. Foth 와 Rust 는 C보다 메모리 제한이 더 많은 언어의 두 가지 예입니다. malloc()
(1) 프로그램이 결정 가능한 세트 외부에 쓰여지는지를 감지 할 수 있습니다. (2) 인서트 할당 해제를 자동으로 수행합니다.
"인간은 그렇게하므로 불가능하지 않다"는 잘 알려진 오류입니다. 우리는 우리가 창출 한 것을 이해하는 것만으로 (독립적으로 통제 할 필요는 없음) 돈이 일반적인 예입니다. 우리는 특히 인적 요소가없는 것처럼 보이는 기술적 문제에서 성공 가능성을 과대 평가하는 경향이 있습니다 (때로는 극적으로).
컴퓨터 프로그래밍에서 인간의 성과는 매우 열악 하며, 컴퓨터 과학에 대한 연구 (많은 전문 교육 프로그램이 부족함)는 왜이 문제가 간단한 해결책이 없는지 이해하는 데 도움이됩니다. 우리는 언젠가는 그리 멀지 않은 직장에서 인공 지능으로 대체 될 수 있습니다. 그럼에도 불구하고 항상 자동으로 할당 해제를 수행하는 일반적인 알고리즘은 없습니다.
자동 메모리 관리 부족은 언어의 특징입니다.
C는 소프트웨어를 쉽게 작성할 수있는 도구가 아닙니다. 컴퓨터가 지시 한대로 무엇이든 할 수 있도록하는 도구입니다. 여기에는 선택한 순간에 메모리 할당 및 할당 해제가 포함됩니다. C는 컴퓨터를 정확하게 제어하려는 경우 또는 언어 / 표준 라이브러리 디자이너가 예상 한 것과 다른 방식으로 작업하려는 경우 사용하는 저수준 언어입니다.
문제는 대부분 역사적인 유물이며 구현이 불가능합니다.
대부분의 C 컴파일러가 코드를 작성하는 방식은 컴파일러가 한 번에 각 소스 파일 만 볼 수 있도록하는 것입니다. 전체 프로그램을 한 번에 보지 못합니다. 하나의 소스 파일이 다른 소스 파일이나 라이브러리에서 함수를 호출 할 때 모든 컴파일러는 함수의 실제 코드가 아니라 함수의 리턴 유형을 가진 헤더 파일을 보게됩니다. 이는 포인터를 반환하는 함수가있을 때 컴파일러가 포인터가 가리키는 메모리를 해제해야하는지 여부를 알 수있는 방법이 없습니다. 결정하는 정보는 해당 시점에 컴파일러에 표시되지 않습니다. 반면에 인간 프로그래머는 포인터로 수행해야 할 작업을 찾기 위해 함수의 소스 코드 나 설명서를 자유롭게 찾을 수 있습니다.
C ++ 11 또는 Rust와 같은 최신 저수준 언어를 살펴보면 포인터 유형에서 메모리 소유권을 명시 적으로 지정하여 문제를 대부분 해결했음을 알 수 있습니다. C ++에서는 unique_ptr<T>
평문 대신 T*
메모리를 보유 unique_ptr<T>
하고 평문과 달리 객체가 범위의 끝에 도달하면 메모리가 해제되도록합니다 T*
. 프로그래머는 메모리를 한 메모리에서 unique_ptr<T>
다른 메모리로 넘길 수 있지만 unique_ptr<T>
메모리를 가리키는 메모리는 항상있을 수 있습니다 . 따라서 누가 메모리를 소유하고 언제 해제해야하는지 명확하게 알 수 있습니다.
이전 버전과의 호환성을 위해 C ++은 여전히 오래된 스타일의 수동 메모리 관리를 허용하므로 버그 보호 또는 보호 방법을 우회 할 수 unique_ptr<T>
있습니다. Rust는 컴파일러 오류를 통해 메모리 소유권 규칙을 적용한다는 점에서 더욱 엄격합니다.
결정 불가능 성, 정지 문제 등은 그렇습니다. C 의미를 고수하면 메모리를 비워야 할 때 모든 프로그램을 결정할 수 없습니다. 그러나 학업이나 버그가있는 소프트웨어가 아닌 대부분의 실제 프로그램의 경우, 언제 무료로 제공해야하는지 아닌지를 결정하는 것이 절대적으로 가능합니다. 그것은 인간이 처음에 언제 자유를 얻을 수 있는지 아닌지를 알아낼 수있는 유일한 이유입니다.
다른 답변은 가비지 수집을 수행 할 수 있는지 여부, 수행 방법에 대한 세부 정보 및 일부 문제에 중점을 두었습니다.
아직 다루어지지 않은 한 가지 문제는 가비지 수집에서 불가피한 지연입니다. C에서 프로그래머가 free ()를 호출하면 해당 메모리를 즉시 재사용 할 수 있습니다. (적어도 이론상!) 따라서 프로그래머는 100MB 구조를 해제하고 1 밀리 초 후에 다른 100MB 구조를 할당하며 전체 메모리 사용량이 동일하게 유지 될 것으로 예상 할 수 있습니다.
가비지 수집에는 적용되지 않습니다. 가비지 수집 시스템은 사용하지 않는 메모리를 힙으로 반환하는 데 약간의 지연이 있으며 이는 중요 할 수 있습니다. 100MB 구조가 범위를 벗어나고 밀리 초 후에 프로그램이 다른 100MB 구조를 설정하면 시스템이 단기간 동안 200MB를 사용한다고 합리적으로 예상 할 수 있습니다. "단기"는 시스템에 따라 밀리 초 또는 초일 수 있지만 여전히 지연이 있습니다.
RAM과 가상 메모리가 많은 PC에서 실행중인 경우에는이 사실을 눈치 채지 못할 것입니다. 그래도 리소스가 제한된 시스템 (예 : 임베디드 시스템 또는 전화)에서 실행중인 경우이를 진지하게 고려해야합니다. 이것은 단지 이론적 인 것이 아닙니다-개인적으로 .NET Compact Framework를 사용하고 C #에서 개발할 때 WinCE 시스템에서 작업 할 때 (장치 종류의 충돌과 같은) 문제를 일으키는 것을 보았습니다.
문제는 할당 해제가 프로그래머가 소스 코드의 다른 부분에서 추론해야하는 것으로 가정합니다. 그렇지 않습니다. "프로그램에서이 시점에서 메모리 참조 FOO는 더 이상 유용하지 않습니다" 는 (프로시 저럴 언어로) 할당 해제 명령문으로 인코딩 될 때까지 프로그래머의 마음에 알려진 정보 입니다.
이론적으로 다른 코드 줄과 다르지 않습니다. 컴파일러가 자동으로 "프로그램에서이 시점에서 레지스터 BAR 입력을 확인하십시오" 또는 "기능 호출이 0이 아닌 경우 현재 서브 루틴 종료 "를 삽입하지 않는 이유는 무엇 입니까? 컴파일러의 관점에서 볼 때 이유는 이 답변에 표시된 "불완전 성" 입니다. 그러나 프로그래머가 아는 모든 것을 말하지 않으면 모든 프로그램이 불완전하게 고통받습니다.
실생활에서 거래 취소는 거친 작업이나 상용구입니다. 우리의 두뇌는 그것들을 자동으로 채우고 그것에 대해 중얼 거린다. "컴파일러는 그것을 더 잘하거나 더 잘 할 수있다"는 정서는 사실이다. 그러나 이론적으로는 다른 언어가 우리에게 더 많은 이론을 선택할 수 있지만 실제로는 그렇지 않습니다.
무슨 일이 됩니다 가비지 콜렉션이있어, 참조 카운팅 (목표 - C, 스위프트)를 사용하여 컴파일러이 있습니다 다. 참조 횟수를 계산하는 사람은 강한 참조주기를 피함으로써 프로그래머의 도움이 필요합니다.
실제 에 응답 전 그 컴파일러 작가가 충분하고 컴파일러가 사용할 수 있도록 충분히 빠른 방법을 알아 내지 못했다은 "왜". 컴파일러 작성자는 일반적으로 매우 영리하기 때문에 충분하고 빠른 방법을 찾기가 매우 어렵다고 결론 내릴 수 있습니다.
그것이 매우 어렵다는 이유 중 하나는 물론 그것이 결정 불가능하기 때문입니다. 컴퓨터 과학에서 "결정 성"에 대해 이야기 할 때 "올바른 결정을 내린다"는 의미입니다. 물론 인간 프로그래머는 올바른 결정에 국한되지 않기 때문에 메모리 할당을 해제 할 위치를 쉽게 결정할 수 있습니다 . 그리고 그들은 종종 잘못된 결정을 내립니다.
C와 같은 언어에서는 프로그래머가 무료로 통화를 삽입해야합니다. 왜 컴파일러가 이것을 자동으로하지 않습니까?
그게 다야. 이것은 C의 디자인입니다. 컴파일러는 메모리 블록 할당의 의도를 알 수 없습니다. 인간은 모든 메모리 블록의 목적을 알고 있기 때문에이 목적을 달성 할 수 있으므로 해방 할 수 있습니다. 그것은 작성되는 프로그램 디자인의 일부입니다.
C는 저수준 언어이므로 메모리 블록을 다른 프로세스 나 다른 프로세서로 전달하는 인스턴스는 매우 빈번합니다. 극단적 인 경우 프로그래머는 의도적으로 메모리 청크를 할당하고 시스템의 다른 부분에 메모리 압력을 가하기 위해 다시는 사용하지 않을 수 있습니다. 컴파일러는 블록이 여전히 필요한지 알 수 없습니다.
C와 같은 언어에서는 프로그래머가 무료로 통화를 삽입해야합니다. 왜 컴파일러가 이것을 자동으로하지 않습니까?
C와 다른 많은 언어들에서, 컴파일 시점에 분명해야하는 경우에 컴파일러가 이와 동등한 기능을 수행 할 수있는 기능이 있습니다 : 자동 지속 변수 (즉, 일반적인 지역 변수)의 사용 . 컴파일러는 이러한 변수를위한 충분한 공간을 마련하고 (정의 된) 수명이 다했을 때 해당 공간을 해제해야합니다.
C99 이후 가변 길이 배열은 C 기능이므로 자동 지속 시간 개체는 원칙적으로 계산 가능한 지속 시간의 동적 할당 개체가 수행하는 C의 거의 모든 기능을 제공합니다. 실제로 C 구현 은 VLA 사용에 실질적인 제한을 둘 수 있습니다. 즉, 스택에 할당되어 크기가 제한 될 수 있습니다. 그러나 이는 언어 설계 고려 사항이 아니라 구현 고려 사항입니다.
의도 된 사용법으로 자동 지속 시간을 제공하지 못하는 객체는 정확하게 컴파일 타임에 수명을 결정할 수없는 객체입니다.