글쎄, C의 malloc / free와 C ++의 메모리 관리를위한 새로운 / 소멸자를 사용하는 것과 같은 것들이 있다는 것을 알고 있지만,이 언어들에 대해 사용자가 메모리를 수동으로 관리하거나 시스템이 자동으로 메모리를 처리하는 옵션이 있습니까 (가비지 수집)?
다소 새로운 질문이지만 다소 약 1 년 동안 CS에만있었습니다.
글쎄, C의 malloc / free와 C ++의 메모리 관리를위한 새로운 / 소멸자를 사용하는 것과 같은 것들이 있다는 것을 알고 있지만,이 언어들에 대해 사용자가 메모리를 수동으로 관리하거나 시스템이 자동으로 메모리를 처리하는 옵션이 있습니까 (가비지 수집)?
다소 새로운 질문이지만 다소 약 1 년 동안 CS에만있었습니다.
답변:
가비지 콜렉션에는 할당 및 / 또는 참조 횟수 추적을위한 데이터 구조가 필요합니다. 이로 인해 메모리, 성능 및 언어의 복잡성이 오버 헤드됩니다. C ++은 "금속에 가깝게"설계되었습니다. 즉, 편의 기능과 비교하여 트레이드 오프의 성능 측면이 더 뛰어납니다. 다른 언어는 그 상충 관계를 다르게 만듭니다. 이것은 언어를 선택할 때 고려해야 할 사항 중 하나입니다.
즉, C ++에는 상당히 가볍고 성능이 좋은 참조 계산 체계가 많이 있지만 언어 자체의 일부가 아닌 상용 및 공개 소스 라이브러리에 있습니다. 객체 수명을 관리하기위한 참조 횟수는 가비지 수집과 동일하지 않지만 동일한 종류의 많은 문제를 해결하며 C ++의 기본 접근 방식에 더 적합합니다.
엄밀히 말하면, C 언어로 된 메모리 관리는 전혀 없습니다. malloc () 및 free ()는 언어의 키워드가 아니라 라이브러리에서 호출되는 함수일뿐입니다. malloc () 및 free ()는 C 표준 라이브러리의 일부이며 C에 대한 표준 호환 구현에 의해 제공 될 것이기 때문에 이러한 차이점은 현재로서는 잘못된 것일 수 있습니다. 그러나 이것은 과거에 항상 사실이 아니 었습니다.
왜 메모리 관리 표준이없는 언어를 원하십니까? 이것은 C의 원점을 '휴대용 어셈블리'로 되돌립니다. 특수한 메모리 관리 기술을 활용하거나 필요로하는 하드웨어 및 알고리즘의 경우가 많이 있습니다. 내가 아는 한, Java의 기본 메모리 관리를 완전히 비활성화하고 자신의 것으로 대체하는 방법은 없습니다. 이는 일부 고성능 / 최소 리소스 상황에서는 허용되지 않습니다. C는 프로그램에서 사용할 인프라를 정확하게 선택할 수있는 거의 완벽한 유연성을 제공합니다. C 언어는 버그가없는 올바른 코드를 작성하는 데 거의 도움이되지 않습니다.
malloc()
또는을 제공하지 않습니다 free()
. (예 : PIC 용 MLAP 컴파일러)
실제로 정답은 안전하고 효율적인 가비지 수집 메커니즘을 만드는 유일한 방법 은 불투명 한 참조에 대해 언어 수준의 지원 을하는 것입니다. (또는, 반대로 부족 직접 메모리 조작을위한 언어 수준의 지원.)
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 와도 호환되는 다른 선택을했습니다. 대부분의 목적. 불행히도, 은색 총알은 없지만 다양한 선택에 익숙하면 현재 빌드하려는 프로그램에 맞는 것을 선택할 수 있습니다.
std::unique_ptr
"불투명 한 참조에 대한 언어 수준의 지원" 이라고 말하고 있습니까? (내가 의미 지원의 종류하지 않았다, 나는 또한 직접 메모리 조작에 대한 지원도 C ++에서 제거하지 않는 한이 충분한 생각하지 않습니다.) 내가 내 대답에 스마트 포인터를 언급 않으며, 나는 고려할 std:unique_ptr
스마트 포인터를 실제로 참조 계산을 수행하기 때문에 참조 수가 0 또는 1 인 (그리고 std::move
참조 카운트 업데이트 메커니즘 인) 특수한 경우 만 지원합니다 .
std::unique_ptr
참조 횟수 std::move
가없고 참조와 전혀 관련이 없습니다 (따라서 "성능이 없음"). 나는 std::shared_ptr
암시 적으로 업데이트 된 참조 카운트를 가지고 있기 때문에 당신의 요점을 알 수 있습니다 std::move
:)
malloc
하고 free
. 예, GC가 훨씬 빠를 수 있습니다. (내가 "할 수있다"고 말
C ++의 강력한 기능을 사용할 때는 필요하지 않기 때문입니다.
Herb Sutter : " 몇 년 동안 글을 쓰지 않았습니다. "
현대 C ++ 코드 작성 : 21 년 10 월에 C ++이 어떻게 발전해 왔는지 참조
경험 많은 C ++ 프로그래머들에게 놀랍습니다.
"모두"가비지 수집기는 메모리에 참조되지 않은 개체가 있고 삭제 된 개체가 있는지 확인하기 위해 정기적으로 실행되는 프로세스입니다. (예, 나는 이것이 지나치게 단순화 된 것임을 알고 있습니다). 이것은 언어의 속성이 아니라 프레임 워크입니다.
- C 및 C ++ 용으로 작성 쓰레기 수집이 있습니다 이 하나의 예는.
언어에 "추가"되지 않은 한 가지 이유는 메모리 관리를 위해 자체 코드를 사용할 때 코드를 사용하지 않는 기존 코드의 양이 많기 때문일 수 있습니다. 또 다른 이유는 C 및 C ++로 작성된 응용 프로그램 유형에 가비지 수집 프로세스와 관련된 오버 헤드가 필요하지 않기 때문일 수 있습니다.
malloc
and free
에 연결하면 올바른 프로그램이 중단됩니다.
free
끝날 때까지 전화하지 않을 것입니다. 그러나 명시 적으로 전화 할 때까지 메모리를 비우지 않는 제안 된 가비지 수집기는 가비지 수집기가 아닙니다 free
.
정확한 인용 부호는 없지만 Bjarne과 Herb Sutter는 다음과 같이 말합니다.
C ++에는 가비지가 없으므로 가비지 수집기가 필요하지 않습니다.
현대 C ++에서는 스마트 포인터를 사용하므로 가비지가 없습니다.
가비지 콜렉션이있는 언어로 디바이스 핸들러를 작성한다고 상상할 수 있습니까? GC가 실행되는 동안 몇 비트가 줄을 벗어날 수 있습니까?
아니면 운영 체제입니까? 커널을 시작하기 전에 가비지 수집을 어떻게 시작할 수 있습니까?
C는 하드웨어 작업에 가까운 낮은 수준으로 설계되었습니다. 문제? 높은 수준의 작업에도 적합한 훌륭한 언어입니다. 언어 전문가는 이러한 용도를 알고 있지만 장치 드라이버, 임베디드 코드 및 운영 체제의 요구 사항을 우선적으로 지원해야합니다.
이 질문에 대한 짧고 지루한 대답은 가비지 수집기를 작성하는 사람들을 위해 비 가비지 수집 언어가 필요하다는 것입니다. 그것은 동시에 메모리 레이아웃을 매우 정밀하게 제어 할 수있는 언어가 개념적으로 쉬운 일이 아닙니다 및 상단에서 실행되는 GC를 가지고 있습니다.
다른 질문은 C와 C ++에 가비지 수집기가없는 이유입니다. 글쎄, 나는 C ++에 두 가지가 있다는 것을 알고 있지만 처음에는 GC로 설계되지 않은 언어와 C ++을 여전히 사용하는 사람들을 다루어야하기 때문에 인기가 없다. 이 시대는 실제로 GC를 그리워하는 종류가 아닙니다.
또한 GC를 지원하지 않는 오래된 언어에 GC를 추가하는 대신 GC를 지원하면서 동일한 구문을 가진 새로운 언어를 만드는 것이 더 쉽습니다. Java와 C #이 좋은 예입니다.
다음과 같은 다양한 문제가 있습니다.
delete
또는 free
명시 적으로 필요와 다르지 않습니다 . GC 접근 방식은 여전히 댕글 링 참조가없는 장점이 있으며 정적 분석은 일부 사례를 포착 할 수 있지만 모든 사례에 대한 완벽한 솔루션은 없습니다.기본적으로 부분적으로 언어의 시대에 관한 것이지만 어쨌든 GC 이외의 언어를위한 장소가 있습니다. 그리고 C ++에서 GC의 부족은 큰 문제가되지 않습니다. 메모리는 다르게 관리되지만 관리되지는 않습니다.
Microsoft의 관리되는 C ++에는 동일한 응용 프로그램에서 GC와 비 GC를 혼합하는 기능이 적어도있어 각각의 이점을 혼합하여 사용할 수는 있지만 실제로 이것이 얼마나 잘 작동하는지 말할 수는 없습니다.
내 관련 답변으로 담당자를 연결하는 링크 ...
가비지 콜렉션은 기본적으로 DMA 가능 하드웨어 용 드라이버 개발에 사용되는 시스템 언어와 호환되지 않습니다.
객체에 대한 유일한 포인터는 일부 주변 장치의 하드웨어 레지스터에 저장 될 수 있습니다. 가비지 콜렉터는 이에 대해 알지 못하므로 오브젝트에 도달 할 수 없다고 생각하고 수집합니다.
이 주장은 GC를 압축하기 위해 두 배가된다. 하드웨어 주변 장치가 사용하는 객체에 대한 메모리 내 참조를주의 깊게 유지하더라도 GC가 객체를 재배치하면 주변 장치 구성 레지스터에 포함 된 포인터를 업데이트하는 방법을 알 수 없습니다.
따라서 이제는 모바일 DMA 버퍼와 GC 관리 객체가 혼합되어 있어야합니다. 즉, 두 가지 모두의 단점이 있습니다.
C & C ++은 예를 들어 임베디드 시스템에서 1MB의 메모리가있는 16 비트 프로세서에서 실행하기 위해 범용으로 사용되는 비교적 낮은 수준의 언어이기 때문에 gc로 메모리를 낭비 할 수 없었습니다.
C ++ 및 C에는 가비지 수집기가 있습니다. C에서는 이것이 어떻게 작동하는지 확실하지 않지만 C ++에서는 RTTI 를 활용 하여 객체 그래프를 동적으로 검색하여 가비지 수집에 사용할 수 있습니다.
내 지식으로는 가비지 수집기가 없으면 Java를 작성할 수 없습니다. 조금만 검색 하면이 결과가 나타납니다 .
Java와 C / C ++의 주요 차이점은 C / C ++에서 선택은 항상 사용자의 선택이지만 Java에서는 종종 옵션에 따라 옵션을 사용하지 않는 것입니다.
다음은 C와 같은 시스템 언어에서 사용할 수없는 GC 고유 문제 목록입니다.
GC는 객체가 관리하는 코드 수준 아래로 실행해야합니다. 커널에는 그러한 수준이 없습니다.
GC는 때때로 관리 코드를 중지해야합니다. 이제 커널에서 어떻게되는지 생각해보십시오. GC가 기존의 모든 메모리 할당을 스캔하는 동안 머신의 모든 처리는 밀리 초 동안 중지됩니다. 이로 인해 엄격한 실시간 요구 사항에서 작동하는 시스템을 만들려는 모든 시도가 중단됩니다.
GC는 포인터와 비 포인터를 구별 할 수 있어야합니다. 즉, 존재하는 모든 메모리 객체를 볼 수 있어야하며 포인터를 찾을 수있는 오프셋 목록을 생성 할 수 있어야합니다.
이 발견은 완벽해야합니다. GC는 발견 한 모든 포인터를 추적 할 수 있어야합니다. 오 탐지를 역 참조하면 충돌이 발생했을 수 있습니다. 허위 부정을 발견하지 못하면 여전히 사용중인 개체가 손상되어 관리 코드가 충돌하거나 데이터가 자동으로 손상 될 수 있습니다.
이를 위해서는 존재하는 모든 단일 객체에 유형 정보가 저장되어야합니다. 그러나 C와 C ++ 모두 형식 정보가없는 일반 오래된 데이터 개체를 허용합니다.
GC는 본질적으로 느린 사업입니다. Java와 친목을 다한 프로그래머는이를 인식하지 못할 수 있지만 Java로 구현되지 않으면 프로그램의 속도가 훨씬 빨라질 수 있습니다. Java를 느리게 만드는 요소 중 하나는 GC입니다. 이것이 바로 Java와 같은 GCed 언어가 슈퍼 컴퓨팅에 사용되는 것을 방해합니다. 기계의 소비 전력이 연간 백만 달러라면 가비지 수집에 10 %를 지불하고 싶지 않습니다.
C 및 C ++는 가능한 모든 사용 사례를 지원하기 위해 작성된 언어입니다. 보시다시피, 이러한 유스 케이스 중 다수는 가비지 콜렉션으로 인해 제외됩니다. 따라서 이러한 사용 사례를 지원하기 위해 C / C ++를 가비지 수집 할 수 없습니다.