가비지 수집은 기본적으로 컴파일 된 언어로 어떻게 작동합니까?


79

스택 오버플로에서 여러 답변을 탐색 한 후 일부 네이티브 컴파일 언어에는 가비지 수집이 있음이 분명합니다 . 그러나 이것이 정확히 어떻게 작동하는지는 분명하지 않습니다.

가비지 수집이 해석 언어와 어떻게 작동하는지 이해합니다. 가비지 콜렉터는 단순히 인터프리터와 함께 실행되며 사용되지 않고 도달 할 수없는 객체를 프로그램 메모리에서 삭제합니다. 그들은 둘 다 함께 달리고 있습니다.

그래도 컴파일 된 언어와 어떻게 작동합니까? 컴파일러가 일단 소스 코드를 대상 코드, 특히 기본 머신 코드로 컴파일하면 완료됩니다. 작업이 끝났습니다. 그렇다면 컴파일 된 프로그램은 어떻게 가비지 수집 될 수 있습니까?

"쓰레기"객체를 삭제하기 위해 프로그램이 실행되는 동안 컴파일러가 CPU와 작동합니까? 또는 컴파일러가 컴파일 된 프로그램의 실행 파일에 최소 가비지 수집기를 포함합니까?

나는 스택 오버플로에 대한이 답변에서 발췌 한이 때문에 후자의 진술이 전자보다 더 타당하다고 생각합니다 .

그러한 프로그래밍 언어 중 하나는 에펠입니다. 대부분의 Eiffel 컴파일러는 이식성의 이유로 C 코드를 생성합니다. 이 C 코드는 표준 C 컴파일러에서 기계 코드를 생성하는 데 사용됩니다. Eiffel 구현은이 컴파일 된 코드에 대해 GC (때로는 정확한 GC)를 제공하며 VM이 필요하지 않습니다. 특히 VisualEiffel 컴파일러는 완전한 GC 지원을 통해 네이티브 x86 머신 코드를 직접 생성했습니다 .

마지막 문장은 컴파일러가 프로그램이 실행되는 동안 가비지 수집기 역할을하는 최종 실행 파일에 일부 프로그램을 포함하고 있음을 나타냅니다.

D 언어 웹 사이트의 가비지 수집에 관한 페이지 는 기본적으로 컴파일되고 선택적인 가비지 수집기가 있습니다. 또한 일부 백그라운드 프로그램이 가비지 수집을 구현하기 위해 원래 실행 프로그램과 함께 실행된다는 것을 암시하는 것 같습니다.

D는 가비지 수집을 지원하는 시스템 프로그래밍 언어입니다. 일반적으로 메모리를 명시 적으로 비울 필요는 없습니다. 필요에 따라 할당 하면 가비지 수집기가 사용하지 않는 모든 메모리를 주기적으로 사용 가능한 메모리 풀로 반환합니다.

이 방법은 위에서 언급 한 경우 입니다 사용 방법을 정확히 작동까요? 컴파일러는 가비지 수집 프로그램의 복사본을 저장하고 생성 한 각 실행 파일에 붙여 넣습니까?

아니면 내 생각에 결함이 있습니까? 그렇다면 컴파일 된 언어에 대한 가비지 수집을 구현하는 데 어떤 방법이 사용되며 어떻게 작동합니까?


1
이 질문에 대한 유권자 투표자가 문제가 무엇인지 정확하게 진술 할 수 있다면 고맙겠습니다.
Christian Dean

6
GC가 기본적으로 특정 프로그래밍 언어 구현에 필요한 라이브러리의 일부라는 사실을 받아들이면 질문의 요지는 GC 자체와는 아무런 관련이 없으며 정적 링크와 동적 링크와 관련이 있습니다.
Theodoros Chatzigiannakis

7
가비지 수집기는에 해당하는 언어를 구현하는 런타임 라이브러리의 일부로 간주 할 수 있습니다 malloc().
Barmar

9
가비지 수집기의 작동은 컴파일 모델이 아닌 할당 자의 특성에 따라 다릅니다 . 할당자는 할당 된 모든 객체를 알고 있습니다. 그것들을 할당했습니다. 이제 필요한 것은 어떤 객체가 아직 살아 있는지 알 수있는 방법이며 컬렉터는 객체를 제외한 모든 객체를 할당 해제 할 수 있습니다. 이 설명의 어떤 것도 컴파일 모델과 관련이 없습니다.
Eric Lippert 2016 년

1
GC는 인터프리터의 기능이 아니라 동적 메모리의 기능입니다.
Dmitry Grigoryev

답변:


52

컴파일 된 언어의 가비지 콜렉션은 해석 된 언어와 동일한 방식으로 작동합니다. Go와 같은 언어는 일반적으로 코드를 미리 처리하기 위해 컴파일되지만 가비지 수집기 추적을 사용합니다.

(추적) 가비지 수집은 일반적으로 현재 실행중인 모든 스레드의 호출 스택을 걷고 시작합니다. 해당 스택의 개체는 항상 존재합니다. 그런 다음 가비지 수집기는 전체 활성 개체 그래프가 검색 될 때까지 활성 개체가 가리키는 모든 개체를 통과합니다.

이 작업을 수행하려면 C와 같은 언어가 제공하지 않는 추가 정보가 필요합니다. 특히, 동일한 정보를 포함하는 모든 객체 레이아웃의 맵뿐만 아니라 모든 포인터 (및 아마도 해당 데이터 유형)의 오프셋을 포함하는 각 함수의 스택 프레임 맵이 필요합니다.

그러나 강력한 유형 보장을 가진 언어 (예 : 다른 데이터 유형에 대한 포인터 캐스트가 허용되지 않는 경우)가 실제로 컴파일시 해당 맵을 계산할 수 있음을 쉽게 알 수 있습니다. 명령 주소와 스택 프레임 맵 간의 연결 및 이진 내부의 데이터 형식과 객체 레이아웃 맵 간의 연결을 간단히 저장합니다. 그런 다음이 정보를 통해 객체 그래프 순회를 수행 할 수 있습니다.

가비지 수집기 자체는 C 표준 라이브러리와 유사하게 프로그램에 연결된 라이브러리 일뿐입니다. 예를 들어,이 라이브러리는 malloc()메모리 압력이 높은 경우 수집 알고리즘을 실행하는 것과 유사한 기능을 제공 할 수 있습니다 .


9
유틸리티 라이브러리와 JIT 컴파일 사이에서 "컴파일에서 네이티브로 컴파일"과 "런타임 환경에서 실행"사이의 라인이 점점 더 흐려지고 있습니다.
corsiKa

6
GC 지원이 제공되지 않는 언어에 대한 정보를 추가하는 것 : C 및 기타 언어는 호출 스택에 대한 정보를 제공하지 않지만 일부 플랫폼 별 코드 (일반적으로 "보수적 가비지 수집"을 구현하는 것이 여전히 가능합니다. 뵘 GC는 실제 프로그램에서 사용이의 예입니다.
Matti Virkkunen 2016 년

2
@corsiKa 아니면 그 라인이 훨씬 더 뚜렷합니다. 이제 우리는 서로 다른 반의어가 아닌 서로 관련이없는 개념임을 알 수 있습니다.
Kroltan

4
컴파일 된 런타임과 해석 된 런타임에서 알아야 할 또 하나의 복잡성은 대답의이 문장과 관련이 있습니다. "(추적) 가비지 수집은 일반적으로 현재 실행중인 모든 스레드의 호출 스택을 걷는 것으로 시작됩니다." 컴파일 된 환경에서 GC를 구현 한 경험은 스택을 추적하는 것만으로는 충분하지 않다는 것입니다. 시작점은 일반적으로 레지스터에서 추적하기에 충분한 시간 동안 스레드를 일시 중단합니다 . 스택에 아직 저장되지 않은 레지스터에 참조가있을 수 있기 때문입니다. 통역의 경우, 이것은 일반적으로 ...
Jules

... 환경은 모든 데이터가 해석 된 스택에 안전하게 저장된다는 것을 통역사가 알고있는 "안전 지점"에서 GC가 발생하도록 환경에서 조정할 수 있기 때문에 문제가됩니다.
Jules

123

컴파일러는 가비지 수집 프로그램의 복사본을 저장하고 생성 한 각 실행 파일에 붙여 넣습니까?

우아하고 이상하게 들리지만, 그렇습니다. 컴파일러에는 가비지 수집 코드 이상의 기능을 포함하는 전체 유틸리티 라이브러리가 있으며이 라이브러리에 대한 호출은 작성하는 각 실행 파일에 삽입됩니다. 이것을 런타임 라이브러리 라고하며 , 일반적으로 얼마나 많은 작업을 수행하는지 놀라게 될 것입니다.


51
@ChristianDean C에도 런타임 라이브러리가 있습니다. 이 GC를 가지고 있지 않지만, 그것은 여전히 런타임 라이브러리를 통해 메모리 관리를 수행 malloc()하고 free()언어에 내장되지는 운영 체제의 일부가 아닌,하지만이 라이브러리의 함수입니다. 언어가 GC를 염두에두고 설계되지 않았더라도 C ++은 가비지 수집 라이브러리로 컴파일되기도합니다.
amon

18
C ++에는 dynamic_castGC를 추가하지 않더라도 make 및 예외와 같은 작업 을 수행하는 런타임 라이브러리가 포함되어 있습니다 .
Sebastian Redl

23
런타임 라이브러리는 반드시 각 실행 파일 (정적 연결이라고 함)에 복사 될 필요는 없으며 라이브러리를 포함하는 이진 경로로만 참조되고 실행시 액세스 될 수 있습니다. 이는 동적 연결입니다.
mouviciel

16
컴파일러는 다른 일이 발생하지 않고 프로그램의 진입 점으로 직접 이동할 필요가 없습니다. 나는 모든 컴파일러가 실제로 호출하기 전에 많은 플랫폼 특정 초기화 코드를 삽입한다는 것을 잘 알고 main()있습니다.이 코드에서 GC 스레드를 실행하는 것은 완벽하게 합법적입니다. GC가 메모리 할당 호출 내에서 수행되지 않는다고 가정하면 런타임에 GC는 실제로 객체의 어떤 부분이 포인터 또는 객체 참조인지 알아야하며 컴파일러는 객체 참조를 포인터로 변환하기 위해 코드를 생성해야합니다. GC가 객체를 재배치하는 경우
millimoose 2016 년

15
@millimoose : 그렇습니다. 예를 들어, GCC에,이 코드 조각입니다 crt0.o( "의 약자 어떤 C R 않은 T의 모든 프로그램 (또는하지 적어도 모든 프로그램과 연결됩니다, IME, 아주 기초") 자유 서 ).
Jörg W Mittag 2018 년

58

또는 컴파일러에 컴파일 된 프로그램 코드에 최소 가비지 수집기가 포함되어 있습니까?

"컴파일러가 프로그램을 가비지 수집을 수행하는 라이브러리와 연결합니다"라고 말하는 이상한 방법입니다. 하지만 그렇습니다.

이것은 특별한 것이 아닙니다. 컴파일러는 보통 수많은 라이브러리를 컴파일하는 프로그램에 연결합니다. 그렇지 않으면 컴파일 된 프로그램은 많은 것들을 처음부터 다시 구현하지 않고는 많은 것을 할 수 없었습니다. 심지어 텍스트를 화면 / 파일에 쓰는 것조차…

그러나 GC가 다른 라이브러리와 다르면 사용자가 호출하는 명시 적 API를 제공합니까?

아니요 : 대부분의 언어에서 런타임 라이브러리는 GC 이외의 공용 API 없이도 많은 비하인드 작업을 수행합니다. 다음 세 가지 예를 고려하십시오.

  1. 예외 전파 및 스택 해제 / 소멸자 호출
  2. 동적 메모리 할당 (가비지 수집이없는 경우에도 C 에서처럼 단순히 함수를 호출하는 것이 아님)
  3. 동적 유형 정보 추적 (캐스트 등).

따라서 가비지 수집 라이브러리는 전혀 특별하지 않으며 Priori 는 프로그램이 미리 컴파일되었는지 여부와 관련이 없습니다.


이것은 3 시간 전에 게시 된 최고 답변 에서 제시 되고 설명 된 포인트 이상의 실질적인 내용을 제공하지 않는 것 같습니다
gnat

11
@gnat 나는 대답이 충분히 강력하지 않기 때문에 유용하고 필요하다고 느꼈다. 비슷한 사실을 언급하지만 가비지 수집을 싱킹하는 것은 완전히 인공적인 구별이라는 것을 지적하지 못한다. 기본적으로 OP의 가정에는 결함이 있으며 가장 큰 대답은 이것을 언급하지 않습니다. 광산은 (“결함이있는”멍청한 용어를 피하면서).
Konrad Rudolph

모든 것이 특별하지는 않지만 , 보통 사람들은 라이브러리를 코드에서 명시 적으로 호출하는 것으로 생각하기 때문에 다소 특별 하다고 말합니다 . 기본적인 언어 의미론의 구현보다는. OP의 잘못된 가정은 컴파일러가 저자가 지정하지 않은 라이브러리 호출로 계측하는 것보다 다소 간단한 방법으로 코드를 변환하는 것이라고 생각합니다.
millimoose 2016 년

7
@millimoose Runtime 라이브러리는 명시적인 사용자 상호 작용없이 다양한 방식으로 백그라운드에서 작동합니다. 예외 전파 및 스택 해제 / 소멸자 호출을 고려하십시오. 동적 메모리 할당 (가비지 수집이없는 경우에도 C 에서처럼 단순히 함수를 호출하는 것이 아님)을 고려하십시오. 동적 유형 정보 처리 (캐스트 등)를 고려하십시오. 따라서 GC는 독특하지 않습니다.
Konrad Rudolph

3
그렇습니다, 나는 그렇게 이상하게 말했음을 인정합니다. 컴파일러가 실제로 그런 식으로 일하는 것에 회의적 이었기 때문입니다. 그러나 이제는 생각해 보니 훨씬 더 의미가 있습니다. 컴파일러는 표준 라이브러리의 다른 부분과 마찬가지로 가비지 수집기를 간단히 연결할 수 있습니다. 내 혼란의 일부는 가비지 수집기를 통역사 구현의 일부로 생각하고 별도의 프로그램이 아니라고 생각했기 때문에 믿습니다.
Christian Dean

23

그래도 컴파일 된 언어와 어떻게 작동합니까?

당신의 말이 잘못되었습니다. 프로그래밍 언어는 A는 사양 일부 기술 보고서 (좋은 예를 들어, 참조로 작성 R5RS을 ). 실제로 특정 언어 구현 (소프트웨어)을 언급하고 있습니다 .

(일부 프로그래밍 언어는 사양이 잘못되었거나, 누락되었거나, 일부 샘플 구현과 일치하지만, 프로그래밍 언어는 동작을 정의합니다 ( 예 : 구문의미 가 있음) . 소프트웨어 제품 은 아니지만 소프트웨어 제품 일 수 있습니다. 일부 프로그래밍 제품에 의해 구현 되며, 많은 프로그래밍 언어에는 여러 가지 구현이 있으며, 특히 "컴파일 된"은 구현에 적용되는 형용사입니다. 일부 프로그래밍 언어는 컴파일러보다 인터프리터에 의해 더 쉽게 구현됩니다.)

컴파일러가 일단 소스 코드를 대상 코드, 특히 기본 머신 코드로 컴파일하면 완료됩니다. 작업이 끝났습니다.

인터프리터와 컴파일러는 의미가 약하며 일부 언어 구현은 둘 다로 간주 될 수 있습니다. 다시 말해, 그 사이에는 연속체가 있습니다. 최신 읽기 용 책 과 생각 바이트 코드 , JIT 컴파일 , 동적 으로 컴파일 된 C 코드를 방출 일부 다음 "플러그인" 한다면 dlopen (3) 동일한 프로세스에 의해 -ed (현재의 시스템에서이이 호환 될 정도로 빠르다 대화 형 REPL은 , 볼 )


나는 GC 핸드북을 읽는 것이 좋습니다 . 대답하려면 전체 책이 필요합니다 . 그 전에 가비지 콜렉션 위키 페이지를 읽으십시오 (아래에서 읽기 전에 읽은 것으로 가정 함).

컴파일 된 언어 구현 의 런타임 시스템 에는 가비지 콜렉터가 포함되어 있으며 컴파일러는 해당 특정 런타임 시스템에 맞는 코드를 생성 합니다. 특히, 할당 프리미티브 (머신 코드로 컴파일 됨)는 런타임 시스템을 호출하거나 호출 할 수 있습니다.

그렇다면 컴파일 된 프로그램은 어떻게 가비지 수집 될 수 있습니까?

런타임 시스템을 사용하고 "친숙하고"호환되는 기계어 코드를 방출하기 만하면됩니다.

여러 가비지 수집 라이브러리, 특히 Boehm GC , Ravenbrook의 MPS 또는 심지어 내 (유지되지 않은) Qish를 찾을 수 있습니다. 그리고 간단한 GC를 코딩하는 것은 그리 어렵지 않습니다 (그러나 디버깅은 어렵고 경쟁적인 GC를 코딩하는 것은 어렵습니다 ).

경우에 따라 컴파일러는 보수적 인 GC (예 : Boehm GC )를 사용합니다. 그러면 코딩 할 것이 많지 않습니다. 보수적 인 GC는 (컴파일러가 할당 루틴을 호출하거나 전체 GC 루틴을 호출 할 때) 때때로 전체 호출 스택을 스캔 하고 호출 스택 에서 (간접적으로) 도달 할 수있는 메모리 영역이 모두 존재한다고 가정합니다. 입력 정보가 ​​유실되므로 보수적 GC 라고합니다 . 호출 스택의 정수가 주소처럼 보이면 따라 오는 등입니다.

다른 (더 어려운) 경우, 런타임은 세대 별 복사 가비지 콜렉션을 제공합니다 (일반적인 예는 Ocaml 컴파일러로, 이러한 GC를 사용하여 Ocaml 코드를 기계 코드로 컴파일합니다). 그런 다음 문제는 호출에서 정확하게 모든 포인터 를 찾는 것입니다. 그중 일부 는 GC에 의해 움직 입니다. 그런 다음 컴파일러는 런타임에서 사용하는 호출 스택 프레임을 설명하는 메타 데이터를 생성합니다. 따라서 호출 규칙ABI 는 해당 구현 (예 : 컴파일러) 및 런타임 시스템에 특정화 되고 있습니다.

어떤 경우에는, 기계 코드는 컴파일러에 의해 생성 된 (실제로는 심지어 폐쇄가 그것을 가리키는) 자체 쓰레기 수집입니다 . 이것은 모든 REPL 상호 작용에 대한 머신 코드를 생성하는 SBCL (Common Common Lisp 구현) 의 경우에 해당합니다 . 또한 코드와 코드 내부에 사용 된 호출 프레임을 설명하는 메타 데이터도 필요합니다.

컴파일러는 가비지 수집 프로그램의 복사본을 저장하고 생성 한 각 실행 파일에 붙여 넣습니까?

일종의. 그러나 런타임 시스템은도에 전달 스크립트 인터프리터, 예를 들어, 수 (Linux 및 여러 가지 다른 POSIX 시스템) 때때로 등 공유 라이브러리를, 수 (2)는 execve오두막 . 또는 ELF 인터프리터는 elf (5)PT_INTERP등을 참조하십시오 .

BTW, 가비지 수집 및 런타임 시스템을 사용하는 언어의 대부분의 컴파일러는 오늘날 무료 소프트웨어 입니다. 소스 코드를 다운로드하여 연구하십시오.


5
명시 적 사양이없는 프로그래밍 언어 구현 이 많이 있음을 의미합니다 . 예, 동의합니다. 그러나 내 요점은 프로그래밍 언어가 소프트웨어 가 아니라는 것입니다 (컴파일러 또는 인터프리터와 같은). 구문과 의미 가있는 것입니다 (아마도 둘 다 잘못 정의되어 있음).
Basile Starynkevitch

4
@KonradRudolph : "정식"과 "사양"에 대한 정의에 전적으로 의존합니다 : -D 루비 1.8과 1.9의 교차로의 작은 부분 집합을 지정하는 ISO / IEC 30170 : 2012 루비 프로그래밍 언어 사양이 있습니다. 일종의 "실행 가능한 스펙"역할을하는 경계 사례의 세트 인 Ruby Spec Suite 가 있습니다 . 그런 다음 David Flanagan과 Yukihiro Matsumoto 의 Ruby 프로그래밍 언어 .
Jörg W Mittag 2018 년

4
또한 Ruby 문서 . Ruby 이슈 트래커 에 대한 이슈 토론 . ruby-core (영어) 및 ruby-dev (일본어) 메일 링리스트에 대한 토론. 공동체의 상식 기대치 (예 : Array#[]O (1) 최악의 경우, Hash#[]O (1) 상각 된 최악의 경우) 그리고 마지막으로 : matz의 뇌.
Jörg W Mittag 2018 년

6
@KonradRudolph : 요점은 : 공식적인 명세가없고 단일 보완만으로도 여전히 "언어"(추상 규칙 및 제한 사항)와 "구현"(그러한 규칙에 따른 코드 처리 프로그램 및 제한 사항). 그리고 구현은 여전히 ​​사소한 것이지만, "코드가 무엇을하든 사양"이라는 사양을 야기합니다. 결국 ISO 사양, RubySpec 및 RDocs가 작성된 방식입니다.
Jörg W Mittag 2018 년

1
보헴의 가비지 수집기를 키우게되어 기쁩니다. OP 컴파일러는 기존 컴파일러에 "부팅"된 경우에도 간단한 가비지 수집 방법을 보여주는 훌륭한 예이므로 OP 연구에 권장합니다.
Cort Ammon

6

이미 좋은 답변이 있지만이 질문 뒤에 오해가 있음을 분명히하고 싶습니다.

"기본적으로 컴파일 된 언어"자체는 없습니다. 예를 들어, 동일한 Java 코드가 이전 전화 (Java Dalvik)에서 해석되고 런타임에 부분적으로 적시에 컴파일되고 새 전화 (ART)에서 컴파일됩니다.

코드를 기본적으로 실행하고 해석하는 것의 차이점은 생각보다 훨씬 덜 엄격합니다. 둘 다 작동하려면 일부 런타임 라이브러리와 일부 운영 체제가 필요합니다 (*). 해석 된 코드에는 인터프리터가 필요하지만 인터프리터는 런타임의 일부일뿐입니다. 그러나 인터프리터를 (Just-In-Time) 컴파일러로 대체 할 수 있기 때문에 이것은 엄격하지 않습니다. 성능을 최대화하려면 데스크탑 Java 런타임에 인터프리터와 두 개의 컴파일러가 포함되어 있어야합니다.

코드 실행 방법에 관계없이 동일하게 작동해야합니다. 메모리 할당 및 해제는 파일 열기, 스레드 시작 등과 같은 런타임 작업입니다. 당신의 언어로 당신은 단지 글을 new X()쓰거나 좋아합니다 . 언어 사양은 어떤 일이 발생해야하며 런타임은이를 수행합니다.

사용 가능한 일부 메모리가 할당되고 생성자가 호출됩니다. 메모리가 충분하지 않으면 가비지 수집기가 호출됩니다. 기본 코드 인 런타임에 이미 있으므로 인터프리터의 존재는 전혀 중요하지 않습니다.

코드 해석과 가비지 수집 사이에는 직접적인 연결이 없습니다. C와 같은 저수준 언어는 모든 것을 신속하고 세밀하게 제어하도록 설계되었으므로 비 네이티브 코드 또는 가비지 수집기의 아이디어에는 적합하지 않습니다. 상관 관계가 있습니다.

예를 들어 Java 인터프리터가 매우 느리고 가비지 수집기가 다소 비효율적 인 예전에는 이것이 사실이었습니다. 요즘에는 상황이 많이 다르며 통역 언어에 대한 말하기는 의미가 없습니다.


(*) 최소한 범용 코드에 대해 말할 때 부트 로더와 비슷한 것을 남겨 두십시오.


Ocaml과 SBCL은 모두 네이티브 컴파일러입니다. 그래서이 있다 "기본적으로 컴파일 된 언어"구현.
Basile Starynkevitch 2016 년

@BasileStarynkevitch WAT? 잘 알려지지 않은 컴파일러의 이름을 내 대답과 어떻게 관련이 있습니까? 원래 해석 된 언어의 컴파일러 인 SBCL이 구별이 의미가 없다는 주장을지지하는 주장이 아닌가?
maaartinus

공통 Lisp (또는 다른 언어)는 해석되거나 컴파일 되지 않습니다 . 프로그래밍 언어 (사양)입니다. 구현은 컴파일러, 인터프리터 또는 그 사이에있는 것 (예 : 바이트 코드 인터프리터) 일 수 있습니다. SBCL은 Common Lisp의 대화식 컴파일 구현입니다. Ocaml은 프로그래밍 언어이기도합니다 (바이트 코드 인터프리터와 네이티브 컴파일러를 구현으로 사용).
Basile Starynkevitch

@BasileStarynkevitch 그것이 내가 주장하는 바입니다. 1. 해석되거나 컴파일 된 언어는 없습니다 (C는 거의 해석되지 않고 LISP는 거의 컴파일되지 않았지만 실제로는 중요하지 않습니다). 2. 가장 잘 알려진 언어에 대한 해석, 컴파일 및 혼합 구현이 있으며 컴파일 또는 해석을 배제하는 언어는 없습니다.
maaartinus

6
나는 당신의 주장이 많은 의미가 있다고 생각합니다. grok의 요점은 항상 "네이티브 프로그램"또는 "never"를 실행하지만보고 싶다는 것입니다. Windows의 exe는 그 자체로는 실행할 수 없습니다. 시작하기 위해 로더와 다른 OS 기능이 필요하며 실제로는 부분적으로 "해석"됩니다. 이것은 .net 실행 파일에서 더 분명해집니다. java myprog만큼 또는 거의 네이티브 grep myname /etc/passwd또는 ld.so myprog그것은 인수를 받아 데이터로 작업을 수행합니다 (그것이 의미하는 무엇이든) 실행은 다음과 같습니다.
피터 A. 슈나이더

3

세부 사항은 구현마다 다르지만 일반적으로 다음과 같은 조합입니다.

  • GC를 포함하는 런타임 라이브러리. 이것은 메모리 할당을 처리하고 "GC_now"기능을 포함한 다른 진입 점이 있습니다.
  • 컴파일러는 데이터 유형이 참조되는 필드를 알 수 있도록 GC에 대한 테이블을 작성합니다. GC가 스택에서 추적 할 수 있도록 각 기능의 스택 프레임에 대해서도 수행됩니다.
  • GC가 증분 (GC 활동이 프로그램과 인터리브 됨)이거나 동시 (별도의 스레드에서 실행) 인 경우, 컴파일러는 참조가 업데이트 될 때 GC 데이터 구조를 업데이트하기위한 특수 오브젝트 코드도 포함합니다. 두 가지 데이터 일관성 문제가 비슷합니다.

증분 및 동시 GC에서 컴파일 된 코드와 GC는 일부 불변을 유지하기 위해 협력해야합니다. 예를 들어 복사 수집기에서 GC는 라이브 데이터를 공간 A에서 공간 B로 복사하여 가비지 뒤에 남겨 둡니다. 다음 사이클에서는 A와 B를 뒤집어 반복합니다. 따라서 사용자 프로그램이 A 공간의 오브젝트를 참조하려고 할 때마다 이것이 감지되고 오브젝트가 즉시 B 공간으로 복사되어 프로그램이 계속 액세스 할 수 있도록하는 규칙이 있습니다. 전달 주소는 공간 A에 남겨 져서 GC에 발생했음을 나타내므로 객체에 대한 다른 참조가 추적 될 때 업데이트됩니다. 이것을 "판독 장벽"이라고합니다.

GC 알고리즘은 60 년대 이래로 연구되어 왔으며이 주제에 대한 광범위한 문헌이 있습니다. 자세한 정보가 필요한 경우 Google

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