C ++에 가비지 수집기가없는 이유는 무엇입니까?


270

가비지 수집의 장점으로 인해이 질문을하지 않습니다. 내가 묻는 주된 이유는 Bjarne Stroustrup이 C ++이 특정 시점에 가비지 수집기를 가질 것이라고 말했다는 것을 알고 있기 때문입니다.

그렇게 말하면서 왜 추가되지 않았습니까? C ++에 대한 가비지 수집기가 이미 있습니다. 이것이 "한 것보다 더 쉬운 말"유형의 것 중 하나입니까? 아니면 추가되지 않은 다른 이유가 있습니까 (C ++ 11에서는 추가되지 않음)?

교차 링크 :

명확히하기 위해 C ++에 가비지 수집기가 처음으로 생성되지 않은 이유를 이해합니다. 수집기를 추가 할 수없는 이유가 궁금합니다.


26
이것은 증오가 항상 제기하는 C ++에 대한 10 가지 신화 중 하나입니다. 가비지 콜렉션은 "내장"되지 않지만 C ++를 수행하는 쉬운 방법이 몇 가지 있습니다. 다른 사람들이 이미 아래에서 할 수있는 것보다 더 나은 답변을했기 때문에 의견 게시 :)
davr

5
그러나 그것이 내장되지 않는 것에 대한 요점입니다. 직접해야합니다. 내장 된 라이브러리, 집에서 만든 것까지 높은 것부터 낮은 것까지의 현실. 나는 C ++을 직접 사용하며 세계 최고의 언어이기 때문에 싫어하지 않습니다. 그러나 동적 메모리 관리는 고통입니다.
QBziZ

4
@Davr-나는 C ++ 증오가 아니며 C ++에 가비지 수집기가 필요하다고 주장조차하지 않습니다. 나는 Bjarne Stroustrup이 추가 될 것이라고 말했기 때문에 묻고 있으며 그것을 구현하지 않은 이유가 무엇인지 궁금합니다.
Jason Baker

1
이 기사에서는 Dr. Dobbs의 C 및 C ++ 용 Boehm 콜렉터에서 C 및 C ++ 과 함께 사용할 수있는 오픈 소스 가비지 콜렉터에 대해 설명합니다. C 표준 소멸자 및 C 표준 라이브러리와 함께 가비지 수집기를 사용할 때 발생하는 일부 문제에 대해 설명합니다.
Richard Chambers

1
@ rogerdpack : 그러나 지금까지는 그렇게 유용하지 않으므로 (내 대답을 참조하십시오 ...) 구현이 구현에 투자하지 않을 것입니다.
einpoklum

답변:


160

암시 적 가비지 콜렉션이 추가되었을 수는 있지만 그저 잘리지 않았습니다. 아마도 구현의 합병증뿐만 아니라 사람들이 일반적인 합의에 빨리 도달 할 수 없기 때문일 것입니다.

Bjarne Stroustrup 자신의 인용문 :

선택적으로 활성화 할 수있는 가비지 수집기가 C ++ 0x의 일부가되기를 희망했지만 그러한 수집기가 다른 언어와 통합되는 방법에 대한 자세한 사양으로 수행해야 할 기술적 인 문제가 충분했습니다. 제공되는 경우 본질적으로 모든 C ++ 0x 기능의 경우와 마찬가지로 실험적인 구현이 존재합니다.

여기서 주제에 대한 좋은 토론이 있습니다 .

일반 개요 :

C ++은 매우 강력하며 거의 모든 작업을 수행 할 수 있습니다. 이러한 이유로 성능에 영향을 줄 수있는 많은 것들을 자동으로 푸시하지는 않습니다. 가비지 수집은 스마트 포인터 (참조 카운트로 포인터를 감싸는 객체로 참조 카운트가 0에 도달하면 자동으로 삭제됨)를 사용하여 쉽게 구현할 수 있습니다.

C ++은 가비지 콜렉션이없는 경쟁자를 염두에두고 작성되었습니다. 효율성은 C ++이 C 및 기타와 비교하여 비판을 피해야하는 주요 관심사였습니다.

가비지 수집에는 두 가지 유형이 있습니다 ...

명시 적 가비지 콜렉션 :

C ++ 0x는 shared_ptr로 작성된 포인터를 통해 가비지 콜렉션을 갖습니다.

당신이 그것을 원한다면 당신은 그것을 사용할 수 있습니다, 당신이 그것을 원하지 않는다면 당신은 그것을 사용하도록 강요되지 않습니다.

C ++ 0x를 기다리지 않으려면 현재 boost : shared_ptr을 사용할 수 있습니다.

암시 적 가비지 콜렉션 :

그러나 투명한 가비지 콜렉션이 없습니다. 향후 C ++ 사양의 초점이 될 것입니다.

Tr1에 암시 적 가비지 콜렉션이없는 이유는 무엇입니까?

이전 인터뷰에서 Bjarne Stroustrup은 tr1이 자신이 원하는 것만 큼을 가지고 있지 않다고 밝혔다.


71
나는 것이 C ++에서 나에게 가비지 수집을 강제하는 경우 증오! 사람들은 왜 사용할 수 smart_ptr's없습니까? 가비지 수집기를 사용하여 로우 레벨 유닉스 스타일의 포크를 어떻게 수행 하시겠습니까? 스레딩과 같은 다른 영향을받습니다. 파이썬은 가비지 콜렉션 때문에 전역 인터프리터 잠금을 주로 가지고 있습니다 (Cython 참조). C / C ++에서 제외하십시오. 감사합니다.
unixman83

26
@ unixman83 : 참조 카운트 가비지 콜렉션 (즉, std::shared_ptr) 의 주요 문제점 은 주기적 참조이며, 이는 메모리 누수를 유발합니다. 따라서 std::weak_ptr사이클을 중단 하는 데 주의해서 사용해야 합니다. 마크 및 스윕 스타일 GC에는이 문제가 없습니다. 스레딩 / 포킹과 가비지 수집 간에는 고유 한 비 호환성이 없습니다. Java와 C #은 모두 고성능 선점 멀티 스레딩과 가비지 수집기를 가지고 있습니다. 대부분의 가비지 수집기는 실행을 중지해야하므로 실시간 응용 프로그램 및 가비지 수집기와 관련하여 문제가 있습니다.
Andrew Tomazos

9
"레퍼런스 카운트 가비지 콜렉션 (예 :) 의 주요 문제점 std::shared_ptr은 주기적 참조입니다."더 나은 성능은 일반적으로 C ++ 사용에 대한 정당성이기 때문에 역겨운
Jon Harrop

11
"저수준 유닉스 스타일 포크를 어떻게하겠습니까?" OCaml과 같은 GC 언어가 20 년 이상 사용해 온 것과 같은 방식입니다.
Jon Harrop

9
"Python은 가비지 수집으로 인해 전역 인터프리터 잠금이 주로 있습니다". 밀짚 꾼 논쟁. Java와 .NET에는 모두 GC가 있지만 전역 잠금은 없습니다.
Jon Harrop

149

토론에 추가하십시오.

가비지 수집에는 알려진 문제가 있으며이를 이해하면 C ++에없는 이유를 이해하는 데 도움이됩니다.

1. 성능?

첫 번째 불만은 종종 성과에 관한 것이지만 대부분의 사람들은 자신이 말하는 것을 실제로 깨닫지 못합니다. Martin Beckett문제에서 알 수 있듯이 성능 자체가 아니라 성능의 예측 가능성입니다.

현재 널리 배포되는 2 가지 GC 제품군이 있습니다.

  • 마크 앤 스윕 종류
  • 참조 카운팅 종류

Mark And Sweep(전체 성능에 미치는 영향) 빠르다 그러나 그것은 "세상을 동결"증후군을 앓고 : 즉, GC가 정리를했다 때까지의 GC의 킥은, 다른 모든 정지시. 몇 밀리 초 안에 응답하는 서버를 구축하려는 경우 일부 트랜잭션은 예상대로 작동하지 않습니다. :)

문제 Reference Counting는 다릅니다. 참조 카운트는 원자 수를 가져야하기 때문에 특히 멀티 스레딩 환경에서 오버 헤드를 추가합니다. 또한 참조주기 문제가 있으므로 이러한주기를 감지하고 제거하기위한 영리한 알고리즘이 필요합니다 (일반적으로 "세계 동결"에 의해 구현되지만 빈도는 낮음). 일반적으로 오늘날 현재이 유형은 (일반적으로 더 반응 적이거나 오히려 얼어 붙지 않지만)보다 느립니다 Mark And Sweep.

에펠 구현 자들이 "세계 정지 (Freeze The World)"측면 없이도 Reference Counting비슷한 글로벌 성능을 가진 가비지 콜렉터 를 구현하려는 논문을 보았습니다 Mark And Sweep. GC에는 별도의 스레드가 필요했습니다 (일반). 알고리즘은 약간 무서웠지만 (종료) 개념은 한 번에 하나씩 개념을 소개하고 "간단한"버전에서 본격적인 알고리즘으로 알고리즘의 진화를 보여주는 데 도움이되었습니다. PDF 파일에 손을 다시 넣을 수있는 경우에만 권장되는 내용 ...

2. 자원 획득이 초기화 (RAII)

C++개체 내에서 리소스의 소유권을 래핑하여 제대로 해제되도록하는 것은 일반적인 관용구입니다 . 가비지 수집이 없기 때문에 주로 메모리에 사용되지만 그럼에도 불구하고 많은 다른 상황에서도 유용합니다.

  • 잠금 (멀티 스레드, 파일 핸들 등)
  • 연결 (데이터베이스, 다른 서버에 대한 ...)

아이디어는 객체의 수명을 올바르게 제어하는 ​​것입니다.

  • 필요한만큼 살아 있어야합니다
  • 당신이 그것으로 끝나면 죽여야한다

GC의 문제는 그것이 전자를 돕고 궁극적으로 나중에 그것을 보장한다면 ...이 "궁극적 인"것으로는 충분하지 않다는 것입니다. 잠금을 해제하면 더 이상 통화를 차단하지 않도록 잠금 해제를 원합니다!

GC를 사용하는 언어에는 두 가지 해결 방법이 있습니다.

  • 스택 할당이 충분할 때 GC를 사용하지 마십시오. 일반적으로 성능 문제에 대한 것이지만 범위가 수명을 정의하므로 실제로 도움이됩니다.
  • usingconstruct ...하지만 C ++ RAII는 암시 적이지만 사용자가 실수로 ( using키워드 를 생략하여 ) 오류를 만들 수 없도록 명시 적 (약한) RAII입니다.

3. 스마트 포인터

스마트 포인터는 종종 메모리를 처리하기 위해 은색 총알로 나타납니다 C++. 스마트 포인터가 있으므로 GC가 필요하지 않은 경우가 종종 있습니다.

하나 더 잘못 될 수 없습니다.

스마트 포인터는 다음 auto_ptr과 같은 unique_ptr이점을 제공합니다. RAII 개념을 사용하면 실제로 매우 유용합니다. 그것들은 매우 간단하여 스스로 쉽게 작성할 수 있습니다.

그러나 소유권을 공유해야하는 경우 더 어려워집니다. 여러 스레드간에 공유 할 수 있으며 개수 처리에 약간의 미묘한 문제가 있습니다. 그러므로 자연스럽게쪽으로갑니다 shared_ptr.

대단합니다. 부스트는 결국 은색 총알이 아닙니다. 사실, 주요 문제 shared_ptr는 구현 된 GC를 에뮬레이트 Reference Counting하지만 직접 사이클 감지를 구현해야한다는 것입니다 ... Urg

물론이 문제가 weak_ptr있지만 불행히도 shared_ptr그주기 때문에 사용에도 불구하고 이미 메모리 누수를 보았습니다 ... 멀티 스레드 환경에 있으면 감지하기가 매우 어렵습니다!

4. 해결책은 무엇입니까?

은 총알은 없지만 항상 그렇듯이 실현 가능합니다. GC가 없으면 소유권에 대해 명확해야합니다.

  • 가능하면 한 번에 한 명의 소유자를 선호합니다
  • 그렇지 않은 경우 클래스 다이어그램에 소유권과 관련된주기가 없는지 확인하고 weak_ptr

실제로 GC를 갖는 것이 좋을 것입니다 ... 그러나 사소한 문제는 아닙니다. 그리고 그 동안 우리는 소매를 굴려야합니다.


2
두 가지 답변을받을 수 있으면 좋겠습니다. 이것은 대단하다. 성능과 관련하여 별도의 스레드에서 실행되는 GC는 실제로 매우 일반적입니다 (Java 및 .Net에서 사용됨). 물론 임베디드 시스템에서는 허용되지 않을 수 있습니다.
Jason Baker

14
두 가지 유형 만? 수집기 복사는 어때? 세대 수집가? 여러 동시 수집가 (베이커의 하드 런닝 머신 포함)? 다양한 하이브리드 수집가? 이 분야의 산업에 대한 무지한 사람이 저를 놀라게합니다.
저의 정확한 의견 JUIN

12
두 가지 유형 만 있다고 말했습니까? 나는 널리 배포 된 2 개가 있다고 말했다. 내가 아는 한, Java 및 C #은 모두 Mark 및 Sweep 알고리즘을 사용합니다 (Java는 참조 계산 알고리즘을 사용했습니다). 더 정확하게 말하자면, C #이 마이너 사이클에는 Generational GC를 사용하고, 메이저 사이클에는 Mark And Sweep을 사용하고, 메모리 조각화를 막기 위해 복사를 사용하는 것보다 나에게는 것 같습니다. 알고리즘의 핵심은 Mark And Sweep이라고 주장합니다. 다른 기술을 사용하는 주류 언어를 알고 있습니까? 나는 항상 배우게되어 기쁘다.
Matthieu M.

3
방금 세 가지를 사용하는 하나의 주류 언어를 명명했습니다.
저의 정확한 의견 JUIN

3
주요 차이점은 세대 별 및 증분 GC가 작업을 중단 할 필요가 없으며 GC 포인터에 액세스 할 때 트리 탐색을 반복하여 너무 많은 오버 헤드없이 단일 스레드 시스템에서 작동하도록 할 수 있다는 것입니다. 수집 할 필요성에 대한 기본 예측과 함께 새 노드 수에 따라 결정될 수 있습니다. 코드에서 노드의 생성 / 수정이 발생한 위치에 대한 데이터를 포함시켜 GC를 더욱 향상시킬 수 있으며,이를 통해 예측을 개선하고 이스케이프 분석을 무료로 이용할 수 있습니다.
Keldon Alleyne

56

어떤 타입? 내장형 세탁기 컨트롤러, 휴대폰, 워크 스테이션 또는 슈퍼 컴퓨터에 최적화해야합니까?
GUI 응답 성 또는 서버 로딩을 우선시해야합니까?
많은 메모리 나 많은 CPU를 사용해야합니까?

C / c ++는 너무 많은 다른 환경에서 사용됩니다. 부스트 스마트 포인터와 같은 것이 대부분의 사용자에게 충분하다고 생각합니다.

편집-자동 가비지 수집기는 성능 문제가 아니기 때문에 (항상 더 많은 서버를 구입할 수 있음) 이는 예측 가능한 성능의 문제입니다.
GC가 언제 시작 될지 모르는 것은 마치 수면제 항공사 조종사를 고용하는 것과 같습니다. 대부분의 시간은 훌륭합니다. 그러나 실제로 응답 성이 필요한 경우!


6
나는 분명히 당신의 요점을 보지만, Java가 거의 많은 응용 프로그램에서 사용되지 않습니까?
Jason Baker

35
아니요. Java는 C ++과 같은 정도로 성능이 보장되지 않는 단순한 이유로 고성능 응용 프로그램에는 적합하지 않습니다. 휴대 전화에서는 찾을 수 있지만 휴대 전화 스위치 나 슈퍼 컴퓨터에서는 찾을 수 없습니다.
자스 러스

11
항상 더 많은 서버를 구입할 수 있지만 고객의 주머니에 이미있는 휴대폰의 CPU를 더 많이 구입할 수는 없습니다!
Crashworks

8
Java는 CPU 효율성에서 많은 성능 캐치를 수행했습니다. 실제로 다루기 힘든 문제는 메모리 사용이며, Java는 본질적으로 C ++보다 메모리 효율성이 떨어집니다. 그리고 그 비 효율성은 그것이 가비지 수집이라는 사실 때문입니다. 가비지 콜렉션은 빠르고 메모리 효율적일 수 없으며 GC 알고리즘의 작동 속도를 살펴보면 분명해집니다.
네이트 CK

2
@Zathrus java는 대기 시간 (부 실시간)이 아니며 메모리 풋 프린트가 아니라 최적화 지트의 처리량 b / c에서 이길 수 있습니다.
gtrak

34

C ++에 가비지 수집 기능이 내장되어 있지 않은 가장 큰 이유 중 하나는 가비지 수집기가 소멸자와 훌륭하게 작동하는 것이 실제로 매우 어렵다는 것입니다. 내가 아는 한 아직 아무도 그것을 완전히 해결하는 방법을 모른다. 처리해야 할 문제가 많이 있습니다.

  • 결정적 수명의 객체 (참조 횟수는 당신에게 제공하지만 GC는 그렇지 않습니다. 그렇게 큰 것은 아니지만).
  • 객체가 가비지 수집 될 때 소멸자가 발생하면 어떻게됩니까? 이를 전달할 수있는 catch 블록이 없으므로 대부분의 언어는이 예외를 무시하지만 C ++에 적합한 솔루션은 아닙니다.
  • 활성화 / 비활성화하는 방법은 무엇입니까? 당연히 컴파일 타임 결정 일지 모르지만 GC 용으로 작성된 코드 대 NOT GC 용으로 작성된 코드는 매우 다르며 호환되지 않을 것입니다. 이것을 어떻게 조정합니까?

이들은 직면 한 몇 가지 문제에 지나지 않습니다.


17
Gjar과 소멸자는 Bjarne의 훌륭한 회피에 의해 해결 된 문제입니다. 소멸자는 GC의 요점이 아니므로 GC 중에는 실행되지 않습니다. C ++의 GC는 무한한 다른 자원이 아니라 무한 메모리 의 개념을 만들기 위해 존재 합니다.
MSalters

2
소멸자가 실행되지 않으면 언어의 의미가 완전히 변경됩니다. 최소한이 키워드에 gcnew라는 새로운 키워드가 필요하다고 생각합니다. 따라서이 객체를 GC로 명시 적으로 허용해야합니다 (따라서 메모리 이외의 리소스를 래핑하는 데 사용해서는 안됩니다).
Greg Rogers

7
이것은 가짜 주장입니다. C ++에는 명시적인 메모리 관리 기능이 있으므로 모든 객체를 언제 해제해야하는지 파악해야합니다. GC를 사용하면 더 나쁘지 않습니다. 오히려 특정 객체가 해제 될 때, 즉 삭제시 특별한 고려가 필요한 객체를 알아내는 것으로 문제가 줄어 듭니다. Java 및 C #에서의 프로그래밍 경험에 따르면 대다수의 객체는 특별히 고려해야 할 사항이 없으며 GC에 안전하게 맡길 수 있습니다. C ++에서 소멸자의 주요 기능 중 하나는 자식 개체를 해제하는 것입니다 .GC는 자동으로 처리합니다.
네이트 CK

2
@ NateC-K : GC에서 비 GC (아마도 가장 큰 것)에서 개선 된 한 가지는 견고한 GC 시스템이 참조가 존재하는 한 모든 참조가 동일한 객체를 계속 가리 키도록 보장하는 능력입니다. Dispose객체를 호출 하면 객체를 사용할 수 없게되지만 객체가 존재했을 때 객체를 가리키는 참조는 죽은 후에도 계속 수행됩니다. 반대로 GC 이외의 시스템에서는 참조가 존재하는 동안 객체를 삭제할 수 있으며 이러한 참조 중 하나가 사용되는 경우 혼란에 대한 제한은 거의 없습니다.
supercat

22

이것은 오래 되었지만 질문 여전히 아무도 언급하지 않은 한 가지 문제가 있습니다. 가비지 수집은 거의 지정할 수 없습니다.

특히 C ++ 표준은 구현에서 해당 동작을 달성하는 방법이 아니라 외부에서 관찰 가능한 동작 측면에서 언어를 지정하는 데 매우 신중합니다. 가비지 컬렉션의 경우, 그러나,이 없는 사실상 외부에서 관찰 할 수있는 행동.

가비지 수집 의 일반적인 아이디어 는 메모리 할당이 성공할 수 있도록 합리적으로 시도해야한다는 것입니다. 불행히도, 가비지 수집기가 작동하더라도 메모리 할당이 성공하도록 보장하는 것은 본질적으로 불가능합니다. 이것은 수집주기 동안 객체를 메모리로 이동시키는 복사 수집기 (또는 이와 유사한 것)를 사용하는 것이 불가능할 수 있기 때문에 어떤 경우에도 어느 정도는 사실이지만 특히 C ++의 경우 특히 그렇습니다.

객체를 이동할 수없는 경우 할당을 수행 할 연속적인 단일 메모리 공간을 만들 수 없습니다. 즉, 힙 (또는 비어있는 저장소 또는 원하는 것을 호출하는 것)이 가능할 것입니다. 시간이 지남에 따라 조각화됩니다. 결과적으로 요청 된 양보다 많은 메모리 여유 공간이 있어도 할당이 성공하지 못하게 할 수 있습니다.

할 수 있지만 일부 반복적으로 할당 정확히 같은 패턴을 반복하는 경우 있음 (본질적으로)라고 보장하고, 처음으로 성공, 그것은 제공, 이후의 반복에 성공 계속 그 할당 된 메모리 반복 사이에 액세스 할 수 없게되었습니다. 그것은 본질적으로 쓸모없는 약한 보증이지만 그것을 강화하려는 합리적인 희망을 볼 수는 없습니다.

그럼에도 불구하고 C ++에 제안 된 것보다 강력합니다. 그만큼이전 제안 [경고 : PDF] (감소되었다) 모든에서 보증 아무것도했다. 28 페이지의 제안서에서, 외부에서 관찰 가능한 행동을 방해하는 것은 단일 (비 규범 적) 메모입니다.

[참고 : 가비지 수집 프로그램의 경우 고품질 호스팅 구현은 회수 할 수없는 메모리 양을 최대화해야합니다. — 끝 노트]

적어도 나를 위해, 이것은 투자 수익에 대한 심각한 의문 됩니다. 우리는 기존 코드를 깨뜨릴 것입니다 (아무도 확실하지는 않지만 확실히 조금), 구현에 대한 새로운 요구 사항과 코드에 대한 새로운 제한을 적용하고, 그 대가로 얻는 것은 전혀 아무것도 아닐까요?

기껏해야 Java를 이용한 테스트를 기반으로하는 프로그램은 해야 동일한 속도로 실행하려면 약 6 배의 메모리가 필요할 것입니다. 더구나 가비지 수집은 처음부터 Java의 일부였습니다 .C ++는 가비지 수집기에 더 많은 제한을 두어 비용 / 혜택 비율이 훨씬 더 나빠질 것입니다 (제안이 보장 한 것을 넘어서고 가정 할지라도) 일부 혜택).

나는 상황을 수학적으로 요약했다 : 이것은 복잡한 상황이다. 모든 수학자가 알고 있듯이 복소수에는 실수와 허수의 두 부분이 있습니다. 우리가 여기있는 것은 실제 비용이지만 (적어도 대부분은) 상상적인 혜택 인 것으로 보입니다.


올바른 작업을 위해 모든 객체를 삭제해야한다고 지정하더라도 삭제 된 객체 만 수집 대상이 될 수 있다고 언급하더라도 참조 추적 가비지 수집에 대한 컴파일러 지원여전히 유용 할 수 있습니다. 삭제 된 포인터 (참조)를 사용하면 정의되지 않은 동작이 발생하지 않고 트랩 될 수 있습니다.
supercat

2
Java에서도 GC는 실제로 유용한 AFAIK를 수행하도록 지정되지 않았습니다. 그것은 free당신을 요구할지도 모릅니다 ( freeC 언어에 대한 분석을 의미 합니다). 그러나 Java는 종료 자 또는 이와 유사한 것을 호출한다고 보장하지 않습니다. 실제로 C ++는 커밋 데이터베이스 쓰기, 파일 핸들 플러시 등을 실행하기 위해 Java 이상의 기능을 수행합니다. Java는 "GC"가 있다고 주장하지만 Java 개발자는 close()항상 세 심하게 전화 해야하며 close()너무 빨리 또는 너무 늦게 전화하지 않도록주의하면서 리소스 관리를 잘 알고 있어야 합니다. C ++은 우리를 그로부터 해방시켜줍니다. ... (계속)
Aaron McDaid

2
.. 잠시 전에 나의 의견은 자바를 비판하기위한 것이 아닙니다. 저는 "가비지 수집"이라는 용어가 매우 이상한 용어라는 것을 관찰하고 있습니다. 사람들이 생각하는 것보다 훨씬 적은 의미이므로 의미를 명확하게하지 않고 논의하기가 어렵습니다.
Aaron McDaid

@AaronMcDaid GC가 비 메모리 리소스를 전혀 지원하지 않는 것은 사실입니다. 운 좋게도 이러한 리소스는 메모리와 비교할 때 거의 할당되지 않습니다. 또한 할당 된 방법으로 90 % 이상을 해제 할 수 있으므로 try (Whatever w=...) {...}해결합니다 (그리고 잊을 때 경고가 나타납니다). 나머지는 RAII에도 문제가 있습니다. close()"항상"이라고 부르는 것은 수만 줄 당 한 번을 의미하기 때문에 그렇게 나쁘지는 않지만 메모리는 거의 모든 Java 라인에 할당됩니다.
maaartinus

15

자동 가비지 수집을 원한다면 C ++에 적합한 상용 및 공개 도메인 가비지 수집기가 있습니다. 가비지 수집이 적합한 응용 프로그램의 경우 C ++은 다른 가비지 수집 언어와 비교하여 성능이 우수한 우수한 가비지 수집 언어입니다. C ++ 의 자동 가비지 콜렉션에 대한 설명은 C ++ 프로그래밍 언어 (제 4 판) 를 참조하십시오 . Hans-J. C 및 C ++ 가비지 수집을위한 Boehm 사이트 ( archive )

또한 C ++는 가비지 수집기없이 메모리 관리를 안전하고 암시 적 으로 허용하는 프로그래밍 기술을 지원합니다 . 가비지 수집은 마지막 선택이며 리소스 관리를위한 불완전한 처리 방법이라고 생각합니다. 그렇다고 결코 유용하지 않다는 의미는 아니며, 많은 상황에서 더 나은 접근 방법이 있다는 것입니다.

출처: http://www.stroustrup.com/bs_faq.html#garbage-collection

이 나던 이유에 관해서는 내가 정확히 기억한다면 GC가 전에이 발명되었다, 내장 , 나는 언어가 여러 가지 이유 (C와 IE 이전 버전과의 호환성 (을))에 대한 GC를 가질 수도 믿지 않는다

도움이 되었기를 바랍니다.


"다른 가비지 수집 언어와 비교할만한 성능". 소환?
Jon Harrop 2016 년

1
링크가 끊어졌습니다. 나는 5 년 전에이 답변을 썼습니다.
Rayne

1
좋아, 나는 Stroustrup이나 Boehm이 아닌이 주장에 대한 독립적 인 검증을 원했습니다. :-)
Jon Harrop 2016 년

12

Stroustrup은 2013 Going Native 컨퍼런스에서 이에 대해 좋은 의견을 남겼습니다.

이 비디오 에서 약 25m50으로 건너 뛰십시오. . (실제로 전체 비디오를 보는 것이 좋지만 가비지 수집에 대해서는 건너 뜁니다.)

객체를 사용하는 것을 피하고 (명시 적으로) 사용하지 않고 객체와 값을 직접 처리하는 것이 쉽고 안전하고 예측 가능하며 읽기 쉽고 가르치기 쉬운 훌륭한 언어를 사용하는 경우 힙을 사용하면 가비지 수집 조차 원하지 않습니다 .

최신 C ++ 및 C ++ 11에 포함 된 기능을 사용하면 제한된 환경을 제외하고 더 이상 가비지 수집이 바람직하지 않습니다. 사실, 훌륭한 가비지 수집기가 주요 C ++ 컴파일러 중 하나에 내장되어 있어도 자주 사용되지는 않을 것이라고 생각합니다. GC를 피하는 것이 더 어렵지 는 않지만 더 쉬울 것 입니다.

그는이 예를 보여줍니다.

void f(int n, int x) {
    Gadget *p = new Gadget{n};
    if(x<100) throw SomeException{};
    if(x<200) return;
    delete p;
}

C ++에서는 안전하지 않습니다. 그러나 Java에서도 안전하지 않습니다! C ++에서 함수가 일찍 반환되면는 delete호출되지 않습니다. 그러나 Java에서와 같이 전체 가비지 콜렉션이있는 경우, 오브젝트가 "향후 어느 시점에"파괴 될 것이라는 제안 만받을뿐입니다 ( 업데이트 : 이보다 더 나쁩니다. 하지파이널 라이저를 호출 할 것을 약속합니다. 가젯에 열린 파일 핸들, 데이터베이스에 대한 연결 또는 나중에 데이터베이스에 쓰기 위해 버퍼링 한 데이터가있는 경우에는 충분하지 않습니다. 이러한 리소스를 최대한 빨리 확보하기 위해 가제트가 완료 되 자마자 파괴되기를 바랍니다. 더 이상 필요하지 않은 수천 개의 데이터베이스 연결로 데이터베이스 서버가 어려움을 겪고 싶지는 않습니다.

그래서 해결책은 무엇입니까? 몇 가지 접근 방식이 있습니다. 대부분의 객체에 사용할 명백한 접근 방식은 다음과 같습니다.

void f(int n, int x) {
    Gadget p = {n};  // Just leave it on the stack (where it belongs!)
    if(x<100) throw SomeException{};
    if(x<200) return;
}

입력하는 데 걸리는 문자 수가 줄어 듭니다. new방해 가되지 않습니다 . Gadget두 번 입력하지 않아도 됩니다. 함수가 끝나면 객체가 파괴됩니다. 이것이 당신이 원하는 것이라면, 이것은 매우 직관적입니다. Gadget같은 동작합니다이야 intdouble. 예측 가능하고 읽기 쉽고 가르치기 쉬운. 모든 것이 '가치'입니다. 때로는 큰 가치가 있지만 포인터 (또는 참조)로 얻는 '먼 거리에서'동작하지 않기 때문에 값을 가르치기가 더 쉽습니다.

대부분의 객체는 객체를 만든 함수에서만 사용되며 자식 함수에 대한 입력으로 전달 될 수 있습니다. 프로그래머는 객체를 반환하거나 광범위하게 분리 된 소프트웨어 부분에서 객체를 공유 할 때 '메모리 관리'에 대해 생각할 필요가 없습니다.

범위와 수명이 중요합니다. 대부분의 경우 수명이 범위와 동일하면 더 쉽습니다. 이해하기 쉽고 가르치기가 더 쉽습니다. 다른 수명을 원할 때, shared_ptr예를 들어 이것을 사용하여 코드를 읽는 것이 분명해야합니다 . 또는 이동 의미를 활용하거나 값으로 (큰) 객체를 반환하거나 unique_ptr.

이것은 효율성 문제처럼 보일 수 있습니다. 가제트를 반환하려면 어떻게해야 foo()합니까? C ++ 11의 이동 의미는 큰 객체를 더 쉽게 반환 할 수있게합니다. 쓰기 Gadget foo() { ... }만하면 작동하고 빠르게 작동합니다. 당신은 &&자신 을 엉망으로 만들 필요가 없으며 , 가치로 물건을 반환하면 언어는 종종 필요한 최적화를 수행 할 수 있습니다. (C ++ 03 이전에도 컴파일러는 불필요한 복사를 피하는 데 크게 도움이되었습니다.)

Stroustrup이 비디오의 다른 부분에서 이야기 한 것처럼 (작은 글씨로) : "컴퓨터 과학자 만이 대상을 복사 한 다음 원본을 파괴해야합니다. (컴퓨터 과학자가 아닌) 기대합니다. "

객체의 사본 하나만 필요하다는 것을 보장 할 수 있으면 객체의 수명을 이해하는 것이 훨씬 쉽습니다. 원하는 평생 정책을 선택할 수 있으며 원하는 경우 가비지 수집이 있습니다. 그러나 다른 접근 방식의 이점을 이해하면 가비지 수집이 환경 설정 목록의 맨 아래에 있습니다.

그래도 문제가 해결되지 않으면을 (를) 사용 unique_ptr하거나 실패 할 수 있습니다 shared_ptr. 잘 작성된 C ++ 11은 메모리 관리와 관련하여 다른 많은 언어보다 짧고 읽기 쉽고 가르치기 쉽습니다.


1
GC는 자원을 획득하지 않은 객체에만 사용해야합니다 (즉, "추가 통지가있을 때까지"다른 엔티티가 자신을 대신하여 작업을 수행하도록 요청). 경우 Gadget를 대신하여 작업을 수행 할 아무것도 요구하지 않습니다 (자바) 의미없는 경우, 원래의 코드는 자바로 완벽하게 안전 할 것 delete문이 제거되었습니다.
supercat

@supercat, 지루한 소멸자를 가진 객체는 흥미 롭습니다. (나는 '지루함'을 정의하지 않았지만 기본적으로 메모리 확보를 제외하고 호출 할 필요가없는 소멸자). 개별 컴파일러 가 '지루한'상태 인 shared_ptr<T>경우 특별히 처리 할 수 ​​있습니다 T. 실제로 해당 유형의 참조 카운터를 관리하지 않고 GC를 사용하기로 결정할 수 있습니다. 이를 통해 개발자가 알 필요없이 GC를 사용할 수 있습니다. A shared_ptr는 단순히 GC 포인터로 볼 수 있습니다 T. 그러나 이것에는 한계가 있으며 많은 프로그램을 느리게 만듭니다.
Aaron McDaid

일부 사용 패턴은 하나와 잘 작동하고 다른 유형과는 잘 작동하지 않기 때문에 올바른 유형 시스템은 GC 및 RAII 관리 힙 객체에 대해 서로 다른 유형을 가져야합니다. .NET이나 자바에서는 문은 string1=string2;(말 그대로 레지스터로드보다 더 아무것도 저장 등록)을 보장하기 위해 모든 잠금을 필요로하지 않는 문자열의 길이에 관계없이 매우 빠르게 실행할 것이다 위의 문이 동시에 실행되면 string2IS 작성되면 string1정의되지 않은 동작없이 이전 값 또는 새 값을 보유합니다.
supercat

C ++에서 a 할당 shared_ptr<String>에는 많은 무대 뒤 동기화가 String필요하며 변수를 동시에 읽고 쓰는 경우 a 할당이 이상하게 작동 할 수 있습니다. String동시에 읽고 쓰기를 원하는 경우는 흔하지 않지만, 예를 들어 일부 코드에서 진행중인 상태 보고서를 다른 스레드에서 사용할 수있게하려면 발생할 수 있습니다. .NET과 Java에서는 그러한 것들이 "작동"합니다.
supercat

1
@curiousguy는 올바른 예방 조치를 취하지 않는 한 아무것도 변경되지 않았습니다 .Java는 생성자가 끝나면 즉시 종료자를 호출 할 수 있습니다. 실제 예제는 다음과 같습니다.“ finalize ()는 Java 8에서 강력하게 도달 가능한 객체를 호출했습니다 .” 결론은이 기능을 절대 사용하지 않는 것입니다. 거의 모든 사람이 언어의 역사적인 디자인 실수에 동의합니다. 우리가 그 조언을 따를 때, 언어는 우리가 사랑하는 결정론을 제공합니다.
Holger

11

현대 C ++에는 가비지 수집이 필요하지 않기 때문입니다.

이 문제에 대한 Bjarne Stroustrup의 FAQ 답변은 다음과 같습니다.

나는 쓰레기를 좋아하지 않습니다. 나는 쓰레기를 좋아하지 않습니다. 가장 이상적인 것은 가비지를 생성하지 않음으로써 가비지 수집기의 필요성을 없애는 것입니다. 이제 가능합니다.


요즘 작성된 코드의 상황 (C ++ 17 및 공식 핵심 지침 )은 다음과 같습니다.

  • 대부분의 메모리 소유권 관련 코드는 라이브러리 (특히 컨테이너를 제공하는 코드)에 있습니다.
  • 대부분의 사용 메모리 소유권을 포함하는 코드는 RAII의 다음 패턴을 , 그래서 할당은 뭔가가 할당 된있는 범위를 종료 할 때 발생하는 파괴의 건설 및 해제에 이루어진다.
  • 당신은 명시 적으로 할당하거나 직접 할당 해제 메모리하지 않습니다 .
  • 원시 포인터 는 메모리를 소유하지 않으므로 (지침을 준수한 경우) 메모리 를 전달하여 누수 할 수 없습니다.
  • 메모리에서 일련의 값의 시작 주소를 어떻게 전달할 것인지 궁금하다면 스팬 을 사용하면됩니다 . 원시 포인터가 필요하지 않습니다.
  • 소유하고있는 "포인터"가 실제로 필요한 경우 C ++의 표준 라이브러리 스마트 포인터 를 사용해야합니다. 누출 될 수없고 매우 효율적입니다 ( ABI가 방해가 될 수는 있지만 ). 또는 "owner pointers"를 사용 하여 범위 경계를 넘어 소유권을 전달할 수 있습니다 . 이들은 흔하지 않으며 명시 적으로 사용해야합니다. 그러나 채택되면 누출에 대한 훌륭한 정적 검사가 가능합니다.

"아 그래?하지만 어때?

... 옛날에 C ++을 쓰는 데 사용했던 방식으로 코드를 작성한다면? "

사실, 당신은 할 수 단지 모든 지침을 무시하고 새는 응용 프로그램 코드를 작성 - 그것은 컴파일하고 실행 (및 누출), 항상 같은 것입니다.

그러나 개발자가 미덕이되어 많은 자제력을 발휘해야하는 것은 "그냥하지 마라"는 상황이 아니다. 부적합한 코드를 작성하는 것이 더 간단하지도 않고 작성하는 것이 더 빠르거나 성능이 더 우수하지도 않습니다. 적합한 코드가 제공하고 기대하는 것과 "임피던스 불일치"가 증가함에 따라 점차 작성하기가 더 어려워 질 것입니다.

... 내가 reintrepret_cast? 아니면 복잡한 포인터 산술을합니까? 아니면 다른 해킹? "

실제로, 마음에두면 지침을 잘 따르더라도 문제를 일으키는 코드를 작성할 수 있습니다. 그러나:

  1. 거의 수행하지 않을 것입니다 (코드의 장소 측면에서, 실행 시간의 일부로 반드시 필요한 것은 아닙니다)
  2. 실수로하지 않고 의도적으로 만 수행합니다.
  3. 그렇게하면 지침을 준수하는 코드베이스에서 두드러지게 나타납니다.
  4. 어쨌든 다른 언어로 GC를 우회하는 일종의 코드입니다.

... 도서관 개발? "

C ++ 라이브러리 개발자 인 경우 원시 포인터가 포함 된 안전하지 않은 코드를 작성해야하며 신중하고 책임감있게 코딩해야하지만 전문가가 작성한 자체적으로 포함 된 코드 조각이며 전문가가 검토합니다.


따라서 Bjarne이 말한 것과 같습니다. 쓰레기를 생산하지 않도록 확실히하지만 일반적으로 쓰레기를 모으는 동기는 없습니다. GC는 C ++에서 문제가되지 않습니다.

사용자 지정 할당 및 할당 해제 전략을 사용하려는 경우 특정 응용 프로그램에서 GC는 흥미로운 문제가 아닙니다. 이를 위해 언어 수준 GC가 아닌 사용자 지정 할당 및 할당 해제를 원할 것입니다.


문자열을 연삭하는 경우 (GC 필요) .. 조각을 만들고 큰 길이의 문자열 배열 (수백 메가 바이트를 생각)을 가지고 있다고 가정하고, 다른 길이로 처리 및 재구성하여 사용하지 않는 문자열을 삭제하고 다른 문자열을 결합하는 등을 상상해보십시오. 대처하기 위해 고급 언어로 전환해야했기 때문에 알고 있습니다. (물론 GC도 만들 수 있습니다).
www-0av-Com

2
@ user1863152 : 사용자 지정 할당자가 유용한 경우입니다. 여전히 언어 통합 GC가 필요하지 않습니다.
einpoklum

einpoklum : 사실. 코스의 말일뿐입니다. 저의 요구 사항은 동적으로 변화하는 갤런의 운송 승객 정보를 처리하는 것이 었습니다. 매혹적인 주제 .. 정말 소프트웨어 철학으로 귀착됩니다.
www-0av-Com

Java 및 .NET 세계로서 GC는 마침내 큰 문제가 있음을 발견했습니다. 오늘날 사소한 소프트웨어를 사용하지 않고 메모리에 수십억 개의 라이브 오브젝트가있는 경우 GC에서 사물을 숨기려면 코드 작성을 시작해야합니다. Java와 .NET에서 GC를 사용하는 것은 부담입니다.
Zach는

10

C ++의 기본 개념은 사용하지 않는 기능에 대해 성능에 영향을 미치지 않는다는 것입니다. 따라서 가비지 수집을 추가하면 일부 프로그램이 C에서 수행하는 방식으로 하드웨어에서 실행되고 일부는 런타임 가상 머신에서 실행됩니다.

타사 가비지 수집 메커니즘에 바인딩 된 스마트 포인터 형식을 사용하는 것을 막을 수있는 것은 없습니다. 나는 COM과 같은 일을하는 마이크로 소프트를 떠올리는 것 같고 잘 진행되지 않았다.


2
GC에 VM이 필요하다고 생각하지 않습니다. 컴파일러는 전역 상태를 업데이트하기 위해 모든 포인터 작업에 코드를 추가 할 수 있으며 필요에 따라 객체를 삭제하는 백그라운드에서 별도의 스레드가 실행됩니다.
user83255

3
나는 동의한다. 가상 머신은 필요하지 않지만, 두 번째로 백그라운드에서와 같이 메모리를 관리하기 시작하면 실제 "전선"을 그대로두고 일종의 VM 상황이 있다는 느낌이 듭니다.
Uri


4

원래 C 언어의 기본 원리 중 하나는 메모리가 일련의 바이트로 구성되어 있으며 코드는 사용되는 정확한 순간에 해당 바이트의 의미에 대해서만 신경 쓰면된다는 것입니다. 최신 C를 사용하면 컴파일러에서 추가 제한을 적용 할 수 있지만 C는 포인터를 바이트 시퀀스로 분해하고 동일한 값을 포함하는 바이트 시퀀스를 포인터로 어셈블 한 다음 해당 포인터를 이전 객체에 액세스하십시오.

이 기능은 일부 응용 프로그램에서는 유용하거나 필수 불가결 할 수 있지만,이 기능을 포함하는 언어는 유용하고 신뢰할 수있는 모든 가비지 수집 기능을 지원하는 기능이 매우 제한적입니다. 컴파일러가 포인터를 구성하는 비트로 수행 된 모든 것을 알지 못하면 포인터를 재구성하기에 충분한 정보가 우주 어딘가에 존재할 수 있는지 알 수있는 방법이 없습니다. 해당 정보를 알고 있어도 컴퓨터가 액세스 할 수없는 방식으로 해당 정보를 저장할 수 있기 때문에 (예 : 포인터를 구성하는 바이트가 누군가가 쓸 수있을 정도로 오랫동안 화면에 표시되었을 수 있음) 그것들은 종이 위에 내려 놓으면) 컴퓨터가 미래에 포인터가 사용될 수 있는지를 아는 것이 사실상 불가능할 수도 있습니다.

많은 가비지 수집 프레임 워크의 흥미로운 단점은 객체 참조가 포함 된 비트 패턴에 의해 정의되지 않고 객체 참조에 보유 된 비트와 다른 곳에 보유 된 다른 정보 사이의 관계에 의해 정의된다는 것입니다. C 및 C ++에서 포인터에 저장된 비트 패턴이 객체를 식별하면 해당 비트 패턴은 객체가 명시 적으로 파괴 될 때까지 해당 객체를 식별합니다. 전형적인 GC 시스템에서, 객체는 한 순간에 비트 패턴 0x1234ABCD로 표현 될 수 있지만, 다음 GC 사이클은 0x1234ABCD에 대한 모든 참조를 0x4321BABE에 대한 참조로 대체 할 수 있으며, 그 결과 객체는 후자의 패턴으로 표현 될 수있다. 객체 참조와 관련된 비트 패턴을 표시 한 다음 나중에 키보드에서 다시 읽더라도,


정말 좋은 지적입니다. 최근에는 포인터에서 약간의 비트를 훔쳤습니다. 그렇지 않으면 어리석은 양의 캐시 누락이 발생하기 때문입니다.
통행

@PasserBy : 64 비트 포인터를 사용하는 응용 프로그램이 스케일 된 32 비트 포인터를 객체 참조로 사용하거나 4GiB의 주소 공간에 거의 모든 것을 유지하고 특수 객체를 사용하여 높은 곳에서 데이터를 저장 / 검색함으로써 더 많은 이점을 얻는 것이 궁금합니다. 속도 저장을 넘어서? 머신은 32 비트 포인터보다 2 배 많은 캐시를 소비 한다는 점을 제외하고 64 비트 포인터의 RAM 소비가 중요하지 않을만큼 충분한 RAM을 가지고 있습니다 .
supercat

3

모든 기술적 이야기는 개념을 지나치게 복잡하게 만듭니다.

모든 메모리에 대해 자동으로 GC를 C ++에 넣으면 웹 브라우저와 같은 것을 고려하십시오. 웹 브라우저는 전체 웹 문서를로드하고 웹 스크립트를 실행해야합니다. 문서 트리에 웹 스크립트 변수를 저장할 수 있습니다. 탭이 많이 열린 브라우저의 BIG 문서에서 GC가 전체 콜렉션을 수행해야 할 때마다 모든 문서 요소도 스캔해야 함을 의미합니다.

대부분의 컴퓨터에서 이것은 PAGE FAULTS가 발생 함을 의미합니다. 따라서 질문에 대답하는 주된 이유는 PAGE FAULTS가 발생하기 때문입니다. PC가 디스크 액세스를 많이 시작할 때이를 알 수 있습니다. 잘못된 포인터를 증명하기 위해 GC가 많은 메모리를 터치해야하기 때문입니다. 많은 메모리를 사용하는 선의의 응용 프로그램을 사용하는 경우 PAGE FAULTS로 인해 모든 컬렉션을 스캔해야하는 경우가 있습니다. 페이지 결함은 가상 메모리가 디스크에서 RAM으로 다시 읽어야 할 때입니다.

따라서 올바른 해결책은 응용 프로그램을 GC가 필요한 부분과 그렇지 않은 부분으로 나누는 것입니다. 위의 웹 브라우저 예제의 경우, 문서 트리가 malloc으로 할당되었지만 Javascript가 GC로 실행 된 경우 GC가 시작될 때마다 작은 메모리 부분과 메모리의 모든 PAGED OUT 요소 만 스캔합니다. 문서 트리를 다시 페이징 할 필요가 없습니다.

이 문제를 더 이해하려면 가상 메모리와 컴퓨터에서 가상 메모리가 어떻게 구현되는지 찾아보십시오. 실제로 RAM이 많지 않은 경우 프로그램에 2GB를 사용할 수 있다는 사실에 관한 것입니다. 32BIt 시스템 용 2GB RAM이 장착 된 최신 컴퓨터에서는 하나의 프로그램 만 실행되는 경우에는 그러한 문제가 아닙니다.

추가적인 예로, 모든 객체를 추적해야하는 전체 컬렉션을 고려하십시오. 먼저 루트를 통해 도달 할 수있는 모든 개체를 스캔해야합니다. 2 단계에서 보이는 모든 물체를 스캔 한 다음 대기중인 소멸자를 스캔하십시오. 그런 다음 모든 페이지로 다시 이동하여 보이지 않는 모든 개체를 끕니다. 이는 많은 페이지가 여러 번 스왑 아웃 및 다시 전환 될 수 있음을 의미합니다.

그래서 짧은 대답은 모든 메모리를 터치 한 결과로 발생하는 PAGE FAULTS의 수는 프로그램의 모든 객체에 대해 전체 GC를 실행할 수 없기 때문에 프로그래머는 GC를 스크립트와 같은 것을 돕기 위해보아야한다는 것입니다. 데이터베이스 작업을 수행하지만 수동 메모리 관리를 통해 정상적인 작업을 수행합니다.

물론 다른 중요한 이유는 전역 변수입니다. 콜렉터가 글로벌 변수 포인터가 GC에 있음을 알기 위해서는 특정 키워드가 필요하므로 기존 C ++ 코드가 작동하지 않습니다.


3

짧은 답변 : 가비지 수집을 효율적으로 (시간과 공간이 약간만) 효율적으로 수행하는 방법을 항상 모릅니다 (가능한 모든 경우에).

긴 대답 : C와 마찬가지로 C ++는 시스템 언어입니다. 이는 운영 체제와 같은 시스템 코드를 작성할 때 사용됨을 의미합니다. 다시 말해 C ++는 C와 마찬가지로 최고의 성능을 발휘 하도록 설계되었습니다. 으로 주요 대상으로 . 언어 표준은 성능 목표를 방해 할 수있는 기능을 추가하지 않습니다.

가비지 수집이 성능을 방해하는 이유는 무엇입니까? 주된 이유는 구현에있어 모든 경우에 최소한의 오버 헤드로 가비지 수집을 수행하는 방법을 모르기 때문입니다. 따라서 C ++ 컴파일러와 런타임 시스템은 항상 가비지 수집을 효율적으로 수행 할 수 없습니다. 반면에 C ++ 프로그래머는 자신의 디자인 / 구현을 알고 가비지 수집을 가장 잘 수행하는 방법을 결정하는 가장 좋은 사람입니다.

마지막으로, 제어 (하드웨어, 세부 사항 등) 및 성능 (시간, 공간, 전력 등)이 주요 제약 조건이 아닌 경우 C ++는 쓰기 도구가 아닙니다. 다른 언어는 필요한 오버 헤드로 더 나은 서비스를 제공하고 더 많은 [숨겨진] 런타임 관리를 제공 할 수 있습니다.


3

C ++과 Java를 비교할 때 C ++은 암시 적 가비지 콜렉션을 염두에두고 설계되지 않았지만 Java는 설계되었습니다.

C 스타일에서 임의의 포인터와 같은 것을 갖는 것은 GC 구현에 나쁠뿐만 아니라 많은 양의 C ++ 레거시 코드에 대한 이전 버전과의 호환성을 파괴합니다.

또한 C ++은 복잡한 런타임 환경이 아닌 독립형 실행 파일로 실행되는 언어입니다.

전체적으로 그렇습니다. 가비지 콜렉션을 C ++에 추가하는 것이 가능할 수도 있지만 연속성을 위해 그렇게하지 않는 것이 좋습니다.


1
메모리 확보 및 소멸자 실행은 완전히 별개의 문제입니다. Java에는 PITA 인 소멸자가 없습니다. GC는 메모리를 비우고 dtor를 실행하지 않습니다.
curiousguy

0

주로 두 가지 이유로 :

  1. 필요하지 않기 때문에 (IMHO)
  2. C ++의 초석 인 RAII와 거의 호환되지 않기 때문에

C ++은 이미 수동 메모리 관리, 스택 할당, RAII, 컨테이너, 자동 포인터, 스마트 포인터 등을 제공합니다. 가비지 콜렉터는 5 분 동안 누가 어떤 오브젝트를 소유해야하는지, 언제 자원을 해제해야하는지 생각하지 않으려는 게으른 프로그래머를위한 것입니다. 이것이 C ++에서하는 일이 아닙니다.


가비지 수집없이 구현하기 어려운 수많은 (최신) 알고리즘이 있습니다. 시간이 흘러 갔다. 혁신은 또한 고급 언어와 (가비지 수집) 잘 일치하는 새로운 통찰력에서 비롯됩니다. 이 중 하나를 GC free C ++로 백 포트하려고 시도하면 도로의 충돌을 알 수 있습니다. (나는 예제를 제공해야한다는 것을 알고 있지만 지금은 서두르고 있습니다. 죄송합니다. 지금 생각할 수있는 것은 참조 카운팅이 작동하지 않는 영구적 인 데이터 구조에 관한 것입니다.)
BitTickler

0

가비지 콜렉션을 부과하는 것은 실제로 낮은 수준에서 높은 수준의 패러다임 전환입니다.

가비지 콜렉션이있는 언어에서 문자열이 처리되는 방식을 살펴보면, 높은 수준의 문자열 조작 기능 만 허용하고 문자열에 대한 2 진 액세스는 허용하지 않습니다. 간단히 말해서, 모든 문자열 함수는 먼저 포인터를 확인하여 바이트를 그리는 경우에도 문자열이 어디에 있는지 확인합니다. 따라서 가비지 콜렉션이있는 언어의 문자열에서 각 바이트를 처리하는 루프를 수행하는 경우 문자열이 언제 이동했는지 알 수 없으므로 각 반복에 대한 기본 위치와 오프셋을 계산해야합니다. 그런 다음 힙, 스택, 스레드 등을 고려해야합니다.

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