C와 C ++와 같은 언어에 가비지 콜렉션이없는 이유는 무엇입니까? [닫은]


57

글쎄, C의 malloc / free와 C ++의 메모리 관리를위한 새로운 / 소멸자를 사용하는 것과 같은 것들이 있다는 것을 알고 있지만,이 언어들에 대해 사용자가 메모리를 수동으로 관리하거나 시스템이 자동으로 메모리를 처리하는 옵션이 있습니까 (가비지 수집)?

다소 새로운 질문이지만 다소 약 1 년 동안 CS에만있었습니다.


9
이번 학기에는 iPhone 개발 모듈이 있습니다. 2 년 동안 Android 용 앱을 코딩 한 후이 질문은 대부분의 수업에 큰 타격을주었습니다. 이제야 비로소 메모리 관리 오류를 추적 할 필요가없고 보일러 플레이트 코드를 작성하지 않아도 Java가 실제로 몇 시간을 절약했는지 알 수 있습니다.
siamii

7
@ NullUserException은 GC를 거의 암시하는 메모리를 회수하는 방법을 지정하지 않기 때문에.
Winston Ewert

1
@ bizso09 : 아직 ARC를 보셨습니까? 당신이 참조 카운팅에 대한 시스템 지원이있어 느린 / 지방 / 비 결정적 GC에 대한 필요가 없습니다 : developer.apple.com/technologies/ios5
JBRWilkinson

3
이 아주 좋은 질문에 대한 답은 종교적인 헛소리로 가득합니다.
abatishchev

1
C 및 C ++에서는 포인터를 가져 와서 int로 캐스트하고 숫자를 추가하는 것이 가능합니다. 나중에 int에서 숫자를 빼고 결과를 포인터로 캐스트합니다. 이전과 같은 포인터를 얻게됩니다. 주소가 다른 값을 가진 변수에만 저장되는 동안 메모리를 수집하지 않는 GC를 구현하는 것이 좋습니다. 나는 예제가 어리 석다는 것을 알고 있지만 XOR 링크 된 목록 은 비슷한 것을 사용합니다. 나는 이것을 답변으로 게시 할 것이지만 질문은 끝났습니다.
Marian Spanik 2016 년

답변:


72

가비지 콜렉션에는 할당 및 / 또는 참조 횟수 추적을위한 데이터 구조가 필요합니다. 이로 인해 메모리, 성능 및 언어의 복잡성이 오버 헤드됩니다. C ++은 "금속에 가깝게"설계되었습니다. 즉, 편의 기능과 비교하여 트레이드 오프의 성능 측면이 더 뛰어납니다. 다른 언어는 그 상충 관계를 다르게 만듭니다. 이것은 언어를 선택할 때 고려해야 할 사항 중 하나입니다.

즉, C ++에는 상당히 가볍고 성능이 좋은 참조 계산 체계가 많이 있지만 언어 자체의 일부가 아닌 상용 및 공개 소스 라이브러리에 있습니다. 객체 수명을 관리하기위한 참조 횟수는 가비지 수집과 동일하지 않지만 동일한 종류의 많은 문제를 해결하며 C ++의 기본 접근 방식에 더 적합합니다.


26
두 번째 문제는 GC가 비 결정적이라는 것입니다. 프로그램이 개체를 "삭제"한 후에도 개체가 메모리에 있거나 없을 수 있습니다. Refcount 수명주기는 결정적이며 마지막 참조가 삭제되면 메모리가 삭제됩니다. 이것은 메모리 효율성뿐만 아니라 디버깅에도 영향을 미칩니다. 일반적인 프로그래밍 오류는 이론적으로 삭제 된 "좀비"개체, 참조 메모리입니다. GC는이 효과를 가릴 가능성이 훨씬 높으며 간헐적이고 추적하기가 매우 어려운 버그를 생성합니다.
kylben

22
-현대 gc는 할당을 추적하거나 참조를 계산하지 않습니다. 그들은 스택에 현재 모두에서 그래프를 구축하고 단지 응축 및 다른 모든 것들 (간체)를 닦아 및 GC는 일반적으로 결과 감소 된 언어의 복잡성. 성능상의 이점조차도 ​​의문의 여지가 있습니다.
Joel Coehoorn

13
어, @kylben, 자동 GC를 언어로 구워낸 요점은 좀비 객체를 참조 하는 것이 불가능하다는 것입니다. GC는 참조 할 수없는 객체 만 해제하기 때문입니다! 수동 메모리 관리에 실수를하면 추적하기 어려운 버그가 발생합니다.
Ben

14
-1, GC는 참조를 계산하지 않습니다. 또한 메모리 사용 및 할당 체계에 따라 GC가 더 빠를 수 있습니다 (메모리 사용 오버 헤드로). 따라서 성능에 대한 논쟁 역시 잘못된 것입니다. 실제로는 금속과 가까운 지점 만 유효합니다.
deadalnix

14
Java와 C # 모두 참조 카운팅을 사용하지 않음 : 참조 카운팅을 기반으로하는 GC 스키마는 비교적 원시적이며 현대 가비지 컬렉터보다 훨씬 더 나쁘게 수행됩니다 (주로 참조를 복사 할 때마다 참조 카운트를 변경하기 위해 메모리 쓰기를 수행해야하기 때문에)
mikera

44

엄밀히 말하면, C 언어로 된 메모리 관리는 전혀 없습니다. malloc () 및 free ()는 언어의 키워드가 아니라 라이브러리에서 호출되는 함수일뿐입니다. malloc () 및 free ()는 C 표준 라이브러리의 일부이며 C에 대한 표준 호환 구현에 의해 제공 될 것이기 때문에 이러한 차이점은 현재로서는 잘못된 것일 수 있습니다. 그러나 이것은 과거에 항상 사실이 아니 었습니다.

왜 메모리 관리 표준이없는 언어를 원하십니까? 이것은 C의 원점을 '휴대용 어셈블리'로 되돌립니다. 특수한 메모리 관리 기술을 활용하거나 필요로하는 하드웨어 및 알고리즘의 경우가 많이 있습니다. 내가 아는 한, Java의 기본 메모리 관리를 완전히 비활성화하고 자신의 것으로 대체하는 방법은 없습니다. 이는 일부 고성능 / 최소 리소스 상황에서는 허용되지 않습니다. C는 프로그램에서 사용할 인프라를 정확하게 선택할 수있는 거의 완벽한 유연성을 제공합니다. C 언어는 버그가없는 올바른 코드를 작성하는 데 거의 도움이되지 않습니다.


2
전체적으로 좋은 답변에 대해 +1 하나, 특히 "지불 된 가격은 C 언어가 올바른 버그없는 코드 작성에 거의 도움이되지 않는다는 것"
Shivan Dragon

2
C에는 메모리 관리 기능이 있지만 작동하지만 사람들은 거의 알아 채지 못합니다. 정적 메모리, 레지스터 및 스택이 있습니다. 힙을 할당하기 시작할 때까지 괜찮습니다. 일을 망치는 것은 힙 할당입니다. Java의 경우 누구나 자신의 Java 런타임을 작성할 수 있습니다. "System 's Java"를 포함하여 선택할 수있는 항목이 많이 있습니다. .NET은 C가 할 수있는 모든 작업을 수행 할 수 있습니다. C ++의 기본 기능보다 뒤떨어집니다 (예 : 클래스는 .NET에서만 관리 됨). 물론 C ++의 모든 기능과 .NET의 모든 기능을 갖춘 C ++. NET도 있습니다.
Luaan

1
@Luaan 저는 "메모리 관리"라는 매우 관대 한 정의라고 말하고 싶습니다. "힙에서 할당을 시작할 때까지는 훌륭하고 멋집니다. 물건을 엉망으로 만드는 힙 할당입니다." 완벽하게 좋은 비행기, 그냥 날 수 없습니다.
Charles E. Grant

1
@ CharlesE.Grant 글쎄, 순전히 기능적인 언어는 그런 종류의 메모리 관리로 모든 것을 할 수 있습니다. 힙 할당이 일부 사용 사례에서 좋은 균형을 유지한다고해서 이것이 모든 언어 / 런타임의 벤치 마크임을 의미하지는 않습니다. 메모리 관리가 "메모리 관리"가되는 것만은 아닙니다. 단지 간단하고 간단하며 장면 뒤에 숨겨져 있기 때문입니다. 정적 메모리 할당을 디자인하는 것은 여전히 ​​메모리 관리이며 스택을 잘 사용하고 다른 것을 사용할 수 있습니다.
Luaan

"모든 표준 준수 구현"은 표준 준수 호스트 환경 구현에만 해당되지 않습니다. 8 비트 또는 16 비트 임베디드 마이크로 컨트롤러에 가장 적합한 일부 플랫폼 / 표준 라이브러리는 malloc()또는을 제공하지 않습니다 free(). (예 : PIC 용 MLAP 컴파일러)
12431234123412341234123

32

실제로 정답은 안전하고 효율적인 가비지 수집 메커니즘을 만드는 유일한 방법 은 불투명 한 참조에 대해 언어 수준의 지원 을하는 것입니다. (또는, 반대로 부족 직접 메모리 조작을위한 언어 수준의 지원.)

Java 및 C #은 조작 할 수없는 특수 참조 유형이 있으므로이를 수행 할 수 있습니다. 이를 통해 런타임은 할당 된 객체를 메모리로 이동하는 것과 같은 일을 자유롭게 수행 할 수 있으며 , 이는 고성능 GC 구현에 중요합니다.

기록을 위해 현대의 GC 구현은 참조 계산을 사용하지 않으므로 완전히 빨간 청어입니다. 최신 GC는 세대 할당을 사용합니다. 여기서 새로운 할당은 스택 할당이 C ++과 같은 언어로 처리되는 방식과 동일하게 처리 된 다음, 여전히 살아있는 새로 할당 된 객체는 별도의 "생존자"공간으로 이동하고 전체 세대 개체의 할당이 한 번에 해제됩니다.

이 방법에는 장단점이 있습니다. 장점은 GC를 지원하는 언어의 힙 할당이 GC를 지원 하지 않는 언어의 스택 할당만큼 빠르다는 것이며, 단점은 파괴되기 전에 정리를 수행해야하는 객체입니다. 별도의 메커니즘 (예 : C #의 using키워드)이 필요하거나 정리 코드가 비 결정적으로 실행됩니다.

고성능 GC의 핵심은 특별한 참조 클래스에 대한 언어 지원이 있어야한다는 것입니다. C는이 언어를 지원하지 않으며 결코 그렇게하지 않을 것입니다. C ++에는 연산자 오버로딩이 있으므로 GC의 포인터 유형을 에뮬레이트 할 수 있지만 신중하게 수행해야합니다. 실제로 Microsoft가 CLR (.NET 런타임)에서 실행되는 C ++의 방언을 만들 때 "C # 스타일 참조"(예 :) Foo^를 "C ++ 스타일 참조"와 구별하기 위한 새로운 구문을 개발해야했습니다. (예 :) Foo&.

C ++의 기능과 C ++ 프로그래머가 정기적으로 사용 하는 것은 실제로 참조 계산 메커니즘 인 스마트 포인터 입니다. 레퍼런스 카운팅을 "true"GC로 생각하지는 않지만 수동 메모리 관리 나 진정한 GC보다 성능이 저하되지만 결정적 파괴의 이점이있는 동일한 이점을 많이 제공합니다.

하루가 끝나면 대답은 실제로 언어 디자인 기능으로 요약됩니다. C는 하나의 선택을했고 C ++은 C와의 역 호환성을 제공하면서도 대부분의 목적에 적합한 대안을 제공하면서 Java와 C #은 C와 호환되지 않지만 C 와도 호환되는 다른 선택을했습니다. 대부분의 목적. 불행히도, 은색 총알은 없지만 다양한 선택에 익숙하면 현재 빌드하려는 프로그램에 맞는 것을 선택할 수 있습니다.


4
이것은 질문에 대한 실제 답변입니다.
coredump

1
c ++ 부분의 경우, 요즘에는 std :: unique_ptr 및 std :: move :)를 참조하십시오.
Niclas Larsson

@NiclasLarsson : 당신의 요점을 잘 모르겠습니다. std::unique_ptr"불투명 한 참조에 대한 언어 수준의 지원" 이라고 말하고 있습니까? (내가 의미 지원의 종류하지 않았다, 나는 또한 직접 메모리 조작에 대한 지원도 C ++에서 제거하지 않는 한이 충분한 생각하지 않습니다.) 내가 내 대답에 스마트 포인터를 언급 않으며, 나는 고려할 std:unique_ptr스마트 포인터를 실제로 참조 계산을 수행하기 때문에 참조 수가 0 또는 1 인 (그리고 std::move참조 카운트 업데이트 메커니즘 인) 특수한 경우 만 지원합니다 .
Daniel Pryden

std::unique_ptr참조 횟수 std::move가없고 참조와 전혀 관련이 없습니다 (따라서 "성능이 없음"). 나는 std::shared_ptr암시 적으로 업데이트 된 참조 카운트를 가지고 있기 때문에 당신의 요점을 알 수 있습니다 std::move:)
Niclas Larsson

2
@ Mike76 : 할당 측면에서 GC 할당자는 스택 할당만큼 빠르게 작동하며 GC는 수천 개의 객체를 동시에 할당 해제 할 수 있습니다. 아무리 당신이 REF-계산 구현, 할당 및 할당 취소와 함께 할 것보다 더 빠를 수 없을 것 malloc하고 free. 예, GC가 훨씬 빠를 수 있습니다. (내가 "할 수있다"고 말
했음

27

C ++의 강력한 기능을 사용할 때는 필요하지 않기 때문입니다.

Herb Sutter : " 몇 년 동안 글을 쓰지 않았습니다. "

현대 C ++ 코드 작성 : 21 10 월에 C ++이 어떻게 발전해 왔는지 참조

경험 많은 C ++ 프로그래머들에게 놀랍습니다.


흥미 롭군 오늘 내 독서 자료.
surfasb

바, 비디오. 그러나 결코 덜 흥미 롭습니다.
surfasb

2
재미있는 비디오. 21 분, 55 분이 최고였습니다. WinRT 호출이 여전히 C ++ / CLI 범프 인 것처럼 보였습니다.
gbjbaanb

2
@ dan04 : 맞습니다. 그러나 C로 작성하면 원하는 것을 얻을 수 있습니다.
DeadMG

6
가비지 수집 환경에서 불필요한 참조가 없는지 확인하는 것보다 스마트 포인터 관리가 더 이상 요구되지 않습니다. GC는 당신의 마음을 읽을 수 없기 때문에 마법도 아닙니다.
Tamás Szelei

15

"모두"가비지 수집기는 메모리에 참조되지 않은 개체가 있고 삭제 된 개체가 있는지 확인하기 위해 정기적으로 실행되는 프로세스입니다. (예, 나는 이것이 지나치게 단순화 된 것임을 알고 있습니다). 이것은 언어의 속성이 아니라 프레임 워크입니다.

- C 및 C ++ 용으로 작성 쓰레기 수집이 있습니다 이 하나의 예는.

언어에 "추가"되지 않은 한 가지 이유는 메모리 관리를 위해 자체 코드를 사용할 때 코드를 사용하지 않는 기존 코드의 양이 많기 때문일 수 있습니다. 또 다른 이유는 C 및 C ++로 작성된 응용 프로그램 유형에 가비지 수집 프로세스와 관련된 오버 헤드가 필요하지 않기 때문일 수 있습니다.


1
그러나 미래에 작성된 프로그램은 가비지 수집기를 사용하기 시작합니다.
Dark Templar

5
가비지 수집은 이론적으로 모든 프로그래밍 언어와 독립적이지만 C / C ++에 유용한 GC를 작성하는 것은 매우 어렵고 심지어 바보 같은 것을 만드는 것은 불가능합니다 (적어도 Java와 같은 바보가 아닙니다)-Java가 가져올 수있는 이유 오프는 통제 된 가상화 환경에서 실행되기 때문입니다. 반대로 Java 언어는 GC 용으로 설계되었으므로 GC를 수행하지 않는 Java 컴파일러를 작성하는 데 어려움을 겪을 수 있습니다.
tdammers

4
@ tdammers : 가비지 수집이 가능한 언어로 지원되어야한다는 데 동의합니다. 그러나 핵심은 가상화 및 제어 환경이 아니라 엄격한 타이핑입니다. C와 C ++는 약하게 타이핑되었으므로 정수 변수에 포인터를 저장하고 오프셋에서 포인터를 재구성하는 것과 콜렉터가 도달 할 수있는 것을 안정적으로 말할 수없는 것들을 허용합니다 (C ++ 11은 나중에 허용 할 수 없습니다) 보수적 인 수집가). Java에서는 항상 참조가 무엇인지 알고 있으므로 네이티브로 컴파일하더라도 정확하게 수집 할 수 있습니다.
Jan Hudec

2
@ ThorbjørnRavnAndersen : 가비지 수집기가 찾을 수없는 방식으로 포인터를 저장하는 유효한 C 프로그램을 작성할 수 있습니다. 그런 다음 가비지 수집기를 mallocand free에 연결하면 올바른 프로그램이 중단됩니다.
Ben Voigt

2
@ ThorbjørnRavnAndersen : 아니오, 내가 free끝날 때까지 전화하지 않을 것입니다. 그러나 명시 적으로 전화 할 때까지 메모리를 비우지 않는 제안 된 가비지 수집기는 가비지 수집기가 아닙니다 free.
Ben Voigt

12

C는 가비지 수집이 거의 옵션이 아닌 시대에 설계되었습니다. 또한 최소한의 메모리와 최소한의 런타임 지원으로 가비지 수집이 일반적으로 작동하지 않는 베어 메탈, 실시간 환경에서 사용하기위한 것입니다. C는 64 * K * 바이트의 메모리를 가진 pdp-11에서 실행 된 첫 번째 유닉스의 구현 언어였습니다 . C ++은 원래 C의 확장이었습니다. 이미 선택 했으므로 가비지 수집을 기존 언어로 이식하는 것은 매우 어렵습니다. 그것은 1 층에서 내장되어야하는 종류입니다.


9

정확한 인용 부호는 없지만 Bjarne과 Herb Sutter는 다음과 같이 말합니다.

C ++에는 가비지가 없으므로 가비지 수집기가 필요하지 않습니다.

현대 C ++에서는 스마트 포인터를 사용하므로 가비지가 없습니다.


1
스마트 포인터 란 무엇입니까?
Dark Templar

11
그렇게 단순하다면 아무도 GC를 구현하지 않았을 것입니다.
deadalnix

7
@deadalnix : 그렇습니다. 아무도 복잡하거나 느리거나 부풀어 오거나 불필요하게 구현하는 사람이 없기 때문입니다. 모든 소프트웨어는 항상 100 % 효율적입니다.
Zach

5
@deadalnix-메모리 관리에 대한 C ++ 접근 방식은 가비지 수집기보다 최신입니다. RAII는 Bjarne Stroustrup이 C ++ 용으로 발명했습니다. 소멸자 정리는 오래된 아이디어이지만 예외 안전을 보장하기위한 규칙이 핵심입니다. 아이디어 자체가 언제 처음 설명되었는지 정확히 알지 못하지만 1998 년에 첫 번째 C ++ 표준이 완성되었으며 Stroustrups "C ++의 디자인 및 진화"는 1994 년까지 공개되지 않았으며 C ++에 대한 예외는 비교적 최근에 추가되었습니다. "Annotated C ++ Reference Manual"이 1990 년에 출판 된 후 나는 믿습니다. GC는 1959 년 Lisp를 위해 발명되었습니다.
Steve314

1
@deadalnix-적어도 하나의 Java VM이 스마트 포인터 클래스를 사용하여 C ++ 스타일 RAII를 사용하여 구현할 수있는 참조 계산 GC를 사용했음을 알고 있습니까? 정확히 기존 VM보다 멀티 스레드 코드에 더 효율적 이기 때문입니다 . www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdf를 참조하십시오. 실제로 C ++에서 이것을 볼 수없는 한 가지 이유는 일반적인 GC 수집입니다. 사이클을 수집 할 수는 있지만 사이클이있을 때 안전한 소멸자 순서를 선택할 수 없으므로 신뢰할 수있는 소멸자 정리를 보장 할 수 없습니다.
Steve314

8

옵션 가비지 수집기를 포함하도록 이러한 언어가 업데이트되지 않은 이유를 묻습니다.

선택적 가비지 콜렉션의 문제점은 다른 모델을 사용하는 코드를 혼합 할 수 없다는 것입니다. 즉, 가비지 수집기를 사용한다고 가정하는 코드를 작성하면 가비지 수집이 해제 된 프로그램에서 가비지 수집기를 사용할 수 없습니다. 그렇게하면 어디에나 유출됩니다.


6

가비지 콜렉션이있는 언어로 디바이스 핸들러를 작성한다고 상상할 수 있습니까? GC가 실행되는 동안 몇 비트가 줄을 벗어날 수 있습니까?

아니면 운영 체제입니까? 커널을 시작하기 전에 가비지 수집을 어떻게 시작할 수 있습니까?

C는 하드웨어 작업에 가까운 낮은 수준으로 설계되었습니다. 문제? 높은 수준의 작업에도 적합한 훌륭한 언어입니다. 언어 전문가는 이러한 용도를 알고 있지만 장치 드라이버, 임베디드 코드 및 운영 체제의 요구 사항을 우선적으로 지원해야합니다.


2
높은 수준에 적합합니까? 나는 키보드에서 음료수를 코로 골랐다.
DeadMG

5
글쎄, 그는 "많은 더 높은 수준의 작업"이라고 말했습니다. 그는 트롤 계산을 할 수 있습니다 (하나, 둘, 많은 ...). 그리고 그는 실제로 무엇보다 높게 말하지 않았습니다. 그러나 농담을 제외하고는 사실입니다. 증거는 C에서 많은 중요한 프로젝트 성공적으로 개발 되었다는 증거입니다. 많은 프로젝트에 대해 더 나은 선택이있을 수 있지만, 실제 프로젝트는 해왔다.
Steve314

일부 관리되는 운영 체제가 있으며 다소 잘 작동합니다. 실제로 전체 시스템을 관리 경우 실제 시나리오에서 관리되는 코드를 사용하면 성능이 저하 되어 관리되지 않는 코드보다 빠릅니다 . 물론 이들은 모두 "연구 OS"입니다. 관리되는 OS 내에서 완전히 가상화 된 관리되지 않는 OS를 만드는 것 외에 기존의 관리되지 않는 코드와 호환되도록하는 방법은 거의 없습니다. 그러나 Microsoft는 서버 코드가 .NET으로 작성되면서 Windows Server를 그 중 하나로 대체 할 수 있다고 제안했습니다.
Luaan

6

이 질문에 대한 짧고 지루한 대답은 가비지 수집기를 작성하는 사람들을 위해 비 가비지 수집 언어가 필요하다는 것입니다. 그것은 동시에 메모리 레이아웃을 매우 정밀하게 제어 할 수있는 언어가 개념적으로 쉬운 일이 아닙니다 상단에서 실행되는 GC를 가지고 있습니다.

다른 질문은 C와 C ++에 가비지 수집기가없는 이유입니다. 글쎄, 나는 C ++에 두 가지가 있다는 것을 알고 있지만 처음에는 GC로 설계되지 않은 언어와 C ++을 여전히 사용하는 사람들을 다루어야하기 때문에 인기가 없다. 이 시대는 실제로 GC를 그리워하는 종류가 아닙니다.

또한 GC를 지원하지 않는 오래된 언어에 GC를 추가하는 대신 GC를 지원하면서 동일한 구문을 가진 새로운 언어를 만드는 것이 더 쉽습니다. Java와 C #이 좋은 예입니다.


1
programmers.se 또는 SO 어딘가에 누군가 누군가가 자체 부트 스트랩 쓰레기 가비지 수집 작업을하고 있다고 주장한 것입니다 .IIRC는 기본적으로 GC 언어를 사용하여 VM을 구현하고 부트 스트랩 하위 집합이 GC 자체를 구현하는 데 사용됩니다. 나는 이름을 잊었다. 내가 살펴봤을 때, 그들은 기본적으로 GC가없는 하위 세트에서 작동하는 GC 수준으로의 도약을 달성하지 못했다는 것이 밝혀졌습니다. 이것은 원칙적 으로 가능하지만 실제로는 AFAIK가 결코 달성되지 못했습니다. 확실히 어려운 일을하는 경우입니다.
Steve314

@ Steve314 : 어디를 찾았는지 기억하고 싶습니다!
hugomg

그것을 발견! Klein VM을 참조 하여 stackoverflow.com/questions/3317329/…에 대한 의견을 참조하십시오 . 그것을 찾는 문제의 일부-질문이 마감되었습니다.
Steve314

BTW-@missingno로 댓글을 시작할 수없는 것 같습니다.
Steve314

@ steve314 :이 스레드가 첨부 된 답변을 얻었으므로 이미 모든 의견에 대한 알림을받습니다. 이 경우 @ 포스트를 수행하는 것은 중복되며 SE에서는 허용되지 않습니다 ( 왜 그런지 묻지 마십시오 ). (실제 원인은 내 번호가 누락 되었기 때문입니다)
hugomg

5

다음과 같은 다양한 문제가 있습니다.

  • GC는 C ++ 이전과 C 이전에 발명되었지만 GC가 실용적으로 널리 채택되기 전에 C와 C ++가 모두 구현되었습니다.
  • 기본 비 GC 언어가 없으면 GC 언어 및 플랫폼을 쉽게 구현할 수 없습니다.
  • GC는 일반적인 타임 스케일 등에서 개발 된 일반적인 애플리케이션 코드에서 비 GC보다 훨씬 효율적이지만, 더 많은 개발 노력이 절충되며 특수 메모리 관리가 범용 GC보다 성능이 우수한 문제가 있습니다. 게다가 C ++는 추가 개발 노력 없이도 대부분의 GC 언어보다 훨씬 효율적입니다.
  • GC는 C ++ 스타일 RAII보다 보편적으로 안전하지 않습니다. RAII는 메모리 이외의 리소스는 기본적으로 안정적이고시기 적절한 소멸자를 지원하므로 자동으로 정리할 수 있습니다. 참조주기 문제로 인해 기존 GC 방법과 결합 할 수 없습니다.
  • GC 언어에는 고유 한 종류의 메모리 누수가 있습니다. 특히 다시는 사용되지 않는 메모리와 관련이 있지만 기존 참조가 존재하지 않았거나 덮어 쓰지 않은 메모리와 관련이 있습니다. 이를 명시 적으로 수행 할 필요는 원칙적으로 delete또는 free명시 적으로 필요와 다르지 않습니다 . GC 접근 방식은 여전히 ​​댕글 링 참조가없는 장점이 있으며 정적 분석은 일부 사례를 포착 할 수 있지만 모든 사례에 대한 완벽한 솔루션은 없습니다.

기본적으로 부분적으로 언어의 시대에 관한 것이지만 어쨌든 GC 이외의 언어를위한 장소가 있습니다. 그리고 C ++에서 GC의 부족은 큰 문제가되지 않습니다. 메모리는 다르게 관리되지만 관리되지는 않습니다.

Microsoft의 관리되는 C ++에는 동일한 응용 프로그램에서 GC와 비 GC를 혼합하는 기능이 적어도있어 각각의 이점을 혼합하여 사용할 수는 있지만 실제로 이것이 얼마나 잘 작동하는지 말할 수는 없습니다.

내 관련 답변으로 담당자를 연결하는 링크 ...


4

가비지 콜렉션은 기본적으로 DMA 가능 하드웨어 용 드라이버 개발에 사용되는 시스템 언어와 호환되지 않습니다.

객체에 대한 유일한 포인터는 일부 주변 장치의 하드웨어 레지스터에 저장 될 수 있습니다. 가비지 콜렉터는 이에 대해 알지 못하므로 오브젝트에 도달 할 수 없다고 생각하고 수집합니다.

이 주장은 GC를 압축하기 위해 두 배가된다. 하드웨어 주변 장치가 사용하는 객체에 대한 메모리 내 참조를주의 깊게 유지하더라도 GC가 객체를 재배치하면 주변 장치 구성 레지스터에 포함 된 포인터를 업데이트하는 방법을 알 수 없습니다.

따라서 이제는 모바일 DMA 버퍼와 GC 관리 객체가 혼합되어 있어야합니다. 즉, 두 가지 모두의 단점이 있습니다.


아마도 각각의 단점은 있지만 각각의 단점은 적고 장점은 동일합니다. 분명히 더 많은 종류의 메모리 관리를 다루는 데에는 복잡성이 있지만 코드 내에서 각 코스에 맞는 말을 선택하면 복잡성을 피할 수 있습니다. 아마, 나는 상상하지만 이론적 인 차이가 있습니다. 나는 이전에 같은 언어로 GC와 비 GC를 혼합하는 것에 대해 추측했지만 장치 드라이버는 아닙니다. 대부분 GC 응용 프로그램이 있지만 수동으로 메모리 관리되는 저수준 데이터 구조 라이브러리가 있습니다.
Steve314

@ Steve314 : 수동으로 해제해야하는 객체를 기억하는 것이 모든 것을 해제하는 것을 기억하는 것만 큼 번거 롭다고 말하지 않습니까? (물론, 스마트 포인터는 어느 쪽이든 도움이 될 수 있으므로 어느 것도 큰 문제가 아닙니다.) 그리고 수동으로 관리되는 객체와 수집 된 / 컴팩트 한 객체에 대해 서로 다른 풀이 필요합니다. 아무것도 아닌 많은 복잡성이 있습니다.
벤 Voigt

2
모든 GC 인 높은 수준의 코드와 GC에서 제외 된 낮은 수준의 코드 사이에 명확한 구분이있는 경우에는 아닙니다. 나는 몇 년 전에 D를 보면서 아이디어를 개발했다. GC를 옵트 아웃 할 수는 있지만 다시 옵트 인 할 수는 없다. B + 트리 라이브러리를 예로 들어 보자. 컨테이너 전체는 GC 여야하지만 데이터 구조 노드는 그렇지 않을 수 있습니다. GC가 분기 노드를 통해 재귀 검색을 수행하는 것보다 리프 노드를 통해 사용자 지정 검색을 수행하는 것이 더 효율적입니다. 그러나 해당 스캔은 포함 된 항목을 GC에보고해야합니다.
Steve314

요점은 그것이 기능에 포함되어 있다는 것입니다. 특별 WRT 메모리 관리로 B + 트리 노드를 치료하는 것은 그들에게 같은 특수 WRT 치료에 차이가 없습니다 되는 B + 트리 노드를. 캡슐화 된 라이브러리이며 응용 프로그램 코드는 GC 동작이 우회 / 특수 사례임을 알 필요가 없습니다. 적어도 그 당시에는 D에서 불가능했습니다. 앞에서 말했듯이 포함 된 항목을 다시 선택하여 GC에 잠재적 GC 루트로보고하는 방법은 없습니다.
Steve314

3

C & C ++은 예를 들어 임베디드 시스템에서 1MB의 메모리가있는 16 비트 프로세서에서 실행하기 위해 범용으로 사용되는 비교적 낮은 수준의 언어이기 때문에 gc로 메모리를 낭비 할 수 없었습니다.


1
"내장 시스템"? C가 표준화 될 때 (1989), 1MB의 메모리를 가진 PC 를 처리 할 수 ​​있어야했습니다 .
dan04

나는 더 최근의 예를 인용했다는 데 동의합니다.
Petruza

1MB ??? 이런 schmoley, 누가 그렇게 많은 RAM이 필요할까요? </ billGates>
Mark K Cowan

2

C ++ 및 C에는 가비지 수집기가 있습니다. C에서는 이것이 어떻게 작동하는지 확실하지 않지만 C ++에서는 RTTI 를 활용 하여 객체 그래프를 동적으로 검색하여 가비지 수집에 사용할 수 있습니다.

내 지식으로는 가비지 수집기가 없으면 Java를 작성할 수 없습니다. 조금만 검색 하면이 결과가 나타납니다 .

Java와 C / C ++의 주요 차이점은 C / C ++에서 선택은 항상 사용자의 선택이지만 Java에서는 종종 옵션에 따라 옵션을 사용하지 않는 것입니다.


또한 전용 가비지 수집기가보다 효율적으로 구현되고 언어에 더 적합합니다. :)
Max

아니요, RTTI를 사용하여 C / C ++에서 객체 그래프를 동적으로 검색 할 수는 없습니다. 모든 것을 망치는 오래된 데이터 개체입니다. 가비지 수집기가 해당 개체 내에서 포인터와 비 포인터를 구별 할 수있게 해주는 오래된 데이터 개체에 RTTI 정보가 저장되어 있지 않습니다. 더 나쁜 것은 포인터가 모든 하드웨어에서 완벽하게 정렬 될 필요는 없기 때문에 16 바이트 객체가 주어지면 64 비트 포인터가 저장 될 수있는 9 개의 가능한 위치가 있으며이 중 2 개만 겹치지 않는다는 것입니다.
cmaster

2

성능과 안전 사이의 균형입니다.

가비지가 Java로 수집된다는 보장은 없으므로 장시간 동안 공간을 사용하여 정지되는 반면 참조되지 않은 객체 (예 : 가비지)를 스캔하면 사용하지 않은 객체를 명시 적으로 삭제하거나 해제하는 것보다 시간이 오래 걸립니다.

물론, 포인터 나 메모리 누수없이 언어를 만들 수 있으므로 올바른 코드를 생성 할 가능성이 높습니다.

때때로이 논쟁에 약간의 '종교적'우위가있을 수 있습니다.


1

다음은 C와 같은 시스템 언어에서 사용할 수없는 GC 고유 문제 목록입니다.

  • GC는 객체가 관리하는 코드 수준 아래로 실행해야합니다. 커널에는 그러한 수준이 없습니다.

  • GC는 때때로 관리 코드를 중지해야합니다. 이제 커널에서 어떻게되는지 생각해보십시오. GC가 기존의 모든 메모리 할당을 스캔하는 동안 머신의 모든 처리는 밀리 초 동안 중지됩니다. 이로 인해 엄격한 실시간 요구 사항에서 작동하는 시스템을 만들려는 모든 시도가 중단됩니다.

  • GC는 포인터와 비 포인터를 구별 할 수 있어야합니다. 즉, 존재하는 모든 메모리 객체를 볼 수 있어야하며 포인터를 찾을 수있는 오프셋 목록을 생성 할 수 있어야합니다.

    이 발견은 완벽해야합니다. GC는 발견 한 모든 포인터를 추적 할 수 있어야합니다. 오 탐지를 역 참조하면 충돌이 발생했을 수 있습니다. 허위 부정을 발견하지 못하면 여전히 사용중인 개체가 손상되어 관리 코드가 충돌하거나 데이터가 자동으로 손상 될 수 있습니다.

    이를 위해서는 존재하는 모든 단일 객체에 유형 정보가 저장되어야합니다. 그러나 C와 C ++ 모두 형식 정보가없는 일반 오래된 데이터 개체를 허용합니다.

  • GC는 본질적으로 느린 사업입니다. Java와 친목을 다한 프로그래머는이를 인식하지 못할 수 있지만 Java로 구현되지 않으면 프로그램의 속도가 훨씬 빨라질 수 있습니다. Java를 느리게 만드는 요소 중 하나는 GC입니다. 이것이 바로 Java와 같은 GCed 언어가 슈퍼 컴퓨팅에 사용되는 것을 방해합니다. 기계의 소비 전력이 연간 백만 달러라면 가비지 수집에 10 %를 지불하고 싶지 않습니다.

C 및 C ++는 가능한 모든 사용 사례를 지원하기 위해 작성된 언어입니다. 보시다시피, 이러한 유스 케이스 중 다수는 가비지 콜렉션으로 인해 제외됩니다. 따라서 이러한 사용 사례를 지원하기 위해 C / C ++를 가비지 수집 할 수 없습니다.

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