수동 메모리 관리보다 가비지 수집 시연


23

가비지 수집 이 (이론적으로) 수동 메모리 관리보다 빠를 수 있는 많은 곳에서 읽었습니다 (허리, 심지어 직접 작성했습니다 ).

그러나, 보여주는 것보다 말하는 것이 쉽지 않습니다.
실제로이 효과가 실제로 나타나는 코드는 본 적이 없습니다.

이 성능 이점을 보여주는 코드를 가진 사람이 있습니까?


5
GC의 문제는 대부분의 구현이 실행이 매우 다른 결과를 가질 수 있도록 결정 아니라는 것이다,하지가 비교할 수있는 권리 변수를 분리하기 어렵다 언급
— 래칫 괴물

@ratchetfreak : 시간의 70 % 만 빠른 예제를 알고 있다면 저도 괜찮습니다. 적어도 처리량 측면에서 두 가지를 비교할 수 있는 방법 이 있어야합니다 (대기 시간이 작동하지 않을 수 있음).
— Mehrdad

1
글쎄, 이것은 수동으로 GC가 수동으로했던 것보다 항상 수동으로 무엇이든 할 수 있기 때문에 약간 까다 롭습니다. 아마도 이것을 "표준"수동 메모리 관리 도구 (malloc () / free (), 소유 한 포인터, 참조 횟수가있는 공유 포인터, 약한 포인터, 사용자 지정 할당 자 없음)로 제한하는 것이 더 낫습니다. 또는 사용자 지정 할당자를 허용하는 경우 (어떤 프로그래머의 유형에 따라 더 현실적이거나 덜 현실적인 것일 수도 있음) 해당 할당 자에 대한 노력을 제한하십시오. 그렇지 않으면 수동 전략 "이 경우 GC가 수행하는 작업 복사"는 항상 GC만큼 빠릅니다.

1
"GC가하는 일을 복사"한다는 것은 "자신의 GC를 구축"한다는 의미는 아닙니다 (이것은 이론적으로 C ++ 11 이상에서 가능 하며 GC에 대한 선택적 지원 을 제공합니다). 나는 같은 의견에서 앞서 말했듯이 "GC가 수동으로 한 일보다 우위에있는 일을한다"는 것을 의미했다. 예를 들어, Cheney와 같은 압축이이 애플리케이션에 많은 도움이되는 경우, 포인터 수정을 처리하기 위해 사용자 정의 스마트 포인터를 사용하여 유사한 할당 + 압축 방식을 수동으로 구현할 수 있습니다. 또한 섀도 스택과 같은 기술을 사용하면 추가 작업을 희생하면서 C 또는 C ++에서 루트 찾기를 수행 할 수 있습니다.

1
@Ike : 괜찮습니다. 내가 왜 질문을했는지보십시오. 그것은 내 질문의 요점이었습니다. 사람들은 이해해야 할 모든 종류의 설명을 제시 하지만 실제로는 자신의 말이 옳다는 것을 증명하는 데모를 제공하도록 요청할 때 모든 사람들이 걸려 넘어집니다. 이 질문의 핵심은 실제로 실제로 일어날 수 있다는 것을 보여줍니다.
— Mehrdad

답변:


26

http://blogs.msdn.com/b/ricom/archive/2005/05/10/416151.aspx를 참조 하고 모든 링크를 따라 Rico Mariani와 Raymond Chen (Microsoft의 유능한 프로그래머 모두)의 결의를 확인하십시오. . Raymond는 관리되지 않는 것을 개선하고 Rico는 관리되는 것과 동일한 것을 최적화하여 대응합니다.

본질적으로 최적화 노력이 필요하지 않기 때문에 관리되는 버전은 수동보다 몇 배나 빨리 시작되었습니다. 결국 매뉴얼은 관리 대상을 능가하지만 대부분의 프로그래머가 가고 싶지 않은 수준으로 최적화해야합니다. 모든 버전에서 매뉴얼의 메모리 사용량은 관리되는 것보다 훨씬 낫습니다.


실제 예를 인용 +1 코드를 C ++ 구조 (예 :의 적절한 사용은 비록 :) swap)하지 않는 것이 어렵다, 그리고 아마 아주 쉽게 성능 지혜가 당신을 얻을 것이다 ...
— 메흐 다드

5
성능면에서 Raymond Chen을 능가 할 수 있습니다. 나는 그가 아프기 때문에 그가 외면하지 않는 한, 수없이 열심히 일하고 있고, 운이 좋았다고 확신합니다. 왜 그가 당신이 선택한 솔루션을 선택하지 않았는지 모르겠습니다. 나는 그가 이유가 있다고 확신한다
— btilly

Raymond의 코드를 여기에 복사 하고 비교하기 위해 여기 에 내 자신의 버전을 작성 했습니다 . 텍스트 파일이 포함 된 ZIP 파일은 여기에 있습니다 . 내 컴퓨터에서 광산은 14ms에서, Raymond는 21ms에서 실행됩니다. 나는 (가능하다) 뭔가 잘못했다하지 않는 한, 자신의 215 줄의 코드도 50 % 느리게 내 48 줄 구현보다 없이 메모리 매핑 된 파일 또는 사용자 정의 메모리 풀을 (그가 사용했던하는)를 사용. 광산은 C # 버전의 절반입니다. 내가 잘못 했습니까, 아니면 같은 일을 관찰합니까?
— Mehrdad

1
@Mehrdad이 랩톱에서 gcc의 오래된 사본을 꺼내면 코드와 코드가 컴파일되지 않고 아무것도 할 수 없다고보고 할 수 있습니다. 내가 Windows에 있지 않다는 사실이 그 사실을 설명합니다. 그러나 숫자와 코드가 정확하다고 가정 해 봅시다. 그들은 10 년 된 컴파일러와 컴퓨터에서 동일한 성능을 발휘합니까? (블로그가 작성된 시점을 살펴보십시오.) 아마도 아닐 수도 있습니다. 그들이 (C 프로그래머 인) C ++을 올바르게 사용하는 방법을 모른다고 가정 해 봅시다. 우리는 무엇을 남겼습니까?
— btilly

1
우리는 관리되는 메모리로 변환하고 속도를 높일 수있는 합리적인 C ++ 프로그램을 가지고 있습니다. 그러나 C ++ 버전을 최적화하고 더 멀리 가속화 할 수있는 곳. 우리 모두가 동의하는 것은 관리 코드가 관리되지 않는 것보다 빠를 때 항상 발생하는 일반적인 패턴입니다. 그러나 우리는 여전히 관리되는 버전에서 더 빠른 우수한 프로그래머의 합리적인 코드에 대한 구체적인 예를 가지고 있습니다.
— btilly

5

경험상 무료 점심이 없다는 것입니다.

GC는 수동 메모리 관리의 어려움을 없애고 실수 할 가능성을 줄입니다. 특정 GC 전략이 문제에 대한 최적의 솔루션 인 상황이 있으며,이 경우 해당 전략을 사용하면 벌금이 부과되지 않습니다. 그러나 다른 솔루션이 더 빠른 다른 곳도 있습니다. 항상 낮은 수준에서 더 높은 추상화를 시뮬레이션 할 수 있지만 다른 방법으로는 불가능합니다. 일반적으로 높은 추상화가 낮은 것보다 빠를 수있는 방법이 없다는 것을 효과적으로 증명할 수 있습니다.

GC 는 수동 메모리 관리의 특별한 경우입니다

수동으로 더 나은 성능을 얻으려면 많은 작업이나 오류가 발생하기 쉽지만 다른 이야기입니다.


1
그건 말이되지 않습니다. 몇 가지 구체적인 예를 들자면 : 1) 프로덕션의 할당 자 및 쓰기 장벽은 C가 너무 비효율적이기 때문에 수작업으로 작성된 어셈블러입니다. C 컴파일러에서 수행하지 않는 고급 (기능) 언어로 수행되므로 C에서는 수행 할 수 없습니다. 스택 워킹은 고급 언어로 C 수준 아래에서 수행되는 작업의 또 다른 예입니다.
— Jon Harrop

2
1) 주석을 달려면 특정 코드를 봐야하지만 어셈블러의 손으로 쓴 할당 자 / 장벽이 더 빠르면 손으로 쓴 어셈블러를 사용하십시오. 그것이 GC와 관련이 있는지 확실하지 않습니다. 2) 여기를 살펴보십시오 : stackoverflow.com/a/9814654/441099 요점은 일부 비 GC 언어가 꼬리 재귀 제거를 수행 할 수 있는지 여부는 아닙니다. 요점은 코드를 빠르고 빠르게 변환 할 수 있다는 것입니다. 특정 언어의 컴파일러가 자동으로이를 수행 할 수 있는지 여부는 편의상의 문제입니다. 충분히 낮은 추상화에서 원한다면 언제든지 직접 할 수 있습니다.
— Guy Sirton

1
C의 꼬리 호출 예제는 함수 호출 자체의 특수한 경우에만 작동합니다. C는 호출하는 함수의 일반적인 경우를 처리 할 수 ​​없습니다. 튜링 타르타르는 어셈블러로 떨어지고 개발을위한 무한한 시간을 가정합니다.
— Jon Harrop

3

GC가 수동 방법보다 훨씬 효율적으로 인위적인 상황을 구성하는 것은 쉽습니다. 가비지 수집기에는 하나의 "루트"만 있고 모든 것이 가비지이므로 GC 단계가 즉시 완료됩니다.

당신이 그것에 대해 생각하면, 그것은 프로세스에 할당 된 메모리를 가비지 수집 할 때 사용되는 모델입니다. 프로세스는 죽고, 모든 메모리는 가비지입니다. 실질적인 관점에서도 추적을 남기지 않고 시작, 실행 및 죽는 프로세스는 영원히 시작하고 실행하는 프로세스보다 더 효율적일 수 있습니다.

가비지 수집을 사용하여 언어로 작성된 실제 프로그램의 경우 가비지 수집의 이점은 속도가 아니라 정확성과 단순성입니다.


인공적인 예를 만드는 것이 쉬운 경우 간단한 예를 보여 주시겠습니까?
— Mehrdad

1
@Mehrdad 그는 간단한 것을 설명했다. 종료하기 전에 GC 버전이 가비지 실행을 수행하지 못하는 프로그램을 작성하십시오. 수동 메모리 관리 버전은 물건을 명시 적으로 추적하고 비우기 때문에 속도가 느려집니다.
— btilly

3
@btilly : "종료하기 전에 GC 버전에서 가비지 실행을 수행하지 못하는 프로그램을 작성하십시오." ... 처음에 가비지 수집을 수행하지 않으면 GC의 존재 로 인한 성능 향상이 아니라 작동하는 GC 가 없기 때문에 메모리 누수가 발생합니다 ! 프로그램이 종료되기 전에 C ++을 호출하는 것과 같습니다 . 무의미한 비교입니다. 가비지 수집조차하지 않고 메모리 누수가 발생합니다. 가비지 수집을 시작하지 않으면 가비지 수집이 더 빠르거나 느리다고 말할 수 없습니다.abort()
— Mehrdad

극단적 인 예를 들기 위해서는 자신 만의 힙 및 힙 관리 기능을 갖춘 완전한 시스템을 정의해야합니다.이 시스템은 훌륭한 학생 프로젝트이지만이 마진에 맞지 않을 정도로 너무 큽니다. 비 GC 메모리 관리 방법에 스트레스를 주도록 설계된 방식으로 임의 크기의 배열을 할당하고 할당을 해제하는 프로그램을 작성하면 꽤 잘 수행됩니다.
— ddyer

3
@Mehrdad 아닙니다. 시나리오는 GC 버전이 실행 된 임계 값에 도달하지 않았으며 다른 데이터 세트에서 올바르게 수행되지 않았기 때문입니다. GC 버전에는 그리 좋지 않을 것입니다. 그러나 최종 성능을 예측하는 것은 좋지 않습니다.
— btilly

2

GC는 단순한 메모리 관리 전략이 아니라는 점을 고려해야합니다. 또한 언어 및 런타임 환경의 전체 디자인을 요구하여 비용 (및 이점)을 부과합니다. 예를 들어 GC를 지원하는 언어는 가비지 수집기에서 포인터를 숨길 수없고 일반적으로 신중하게 관리되는 시스템 기본 형식을 제외하고는 구성 할 수없는 형식으로 컴파일해야합니다. 또 다른 고려 사항은 GC가 완료까지 실행되어야하는 일부 단계를 부과하므로 응답 시간 보장을 유지하기가 어렵다는 것입니다.

결과적으로 가비지 수집 된 언어가 있고 동일한 시스템에서 수동으로 관리되는 메모리와 속도를 비교하는 경우 가비지 수집을 사용하지 않더라도 오버 헤드를 지불해야합니다.


2

빠를수록 모호합니다. 그러나 하드웨어가 지원되는 경우 초고속, 인식 할 수 없거나 더 빠를 수 있습니다. 오래 전에 LISP 기계에 대한 설계가있었습니다. 한 사람은 GC를 하드웨어의 메모리 하위 시스템에 내장하여 주 CPU가 그 CPU를 알지 못했습니다. 많은 다른 디자인과 마찬가지로 GC는 일시 중지가 거의 필요없이 메인 프로세서와 동시에 실행되었습니다. 보다 현대적인 디자인은 Azul Systems Vega 3 머신으로, JVM은 전용 프로세서와 일시 정지없는 GC를 사용하여 JVM보다 훨씬 빠르게 Java 코드를 실행합니다. GC (또는 Java)가 얼마나 빠른지 알고 싶다면 Google에 문의하십시오.


2

나는 이것에 대해 꽤 많은 작업을 수행했으며 여기 에 그 중 일부를 설명했습니다 . 나는 C ++에서 Boehm GC를 벤치마킹하여 목록 기반의 n- 퀸 솔버를 실행하는 OCaml의 주식 GC와 C ++로 작성된 사용자 지정 표시 영역 GC를 사용 malloc하지만 해제하지는 않지만 할당 및 해제를 사용하여 할당했습니다 free. OCaml의 GC는 모든 경우에 더 빠릅니다. C ++ 및 OCaml 프로그램은 의도적으로 동일한 할당을 동일한 순서로 수행하도록 작성되었습니다.

물론 64 비트 정수만 사용하고 할당은 사용하지 않고 문제를 해결하기 위해 프로그램을 다시 작성할 수 있습니다. 더 빠르기는하지만 연습의 요점을 잃을 것입니다 (새로운 GC 알고리즘의 성능을 예측하는 것이 C ++에 내장 된 프로토 타입을 사용하여 작업했습니다).

나는 실제 C ++ 코드를 관리되는 언어로 포팅하는 업계에서 수년을 보냈다. 거의 모든 단일 사례에서 나는 상당한 성능 향상을 관찰했으며, 그 중 많은 부분이 GC보다 수동 메모리 관리 때문일 것입니다. 실질적인 한계는 마이크로 벤치 마크에서 달성 할 수있는 것이 아니라 마감일 및 GC 기반 언어가 내가 결코 되돌아 보지 않은 생산성 향상을 제공하기 전에 달성 할 수있는 것입니다. 임베디드 장치 (마이크로 컨트롤러)에서 여전히 C 및 C ++을 사용하지만 지금도 바뀌고 있습니다.


+1 감사합니다. 벤치 마크 코드는 어디에서보고 실행할 수 있습니까?
— Mehrdad

코드는 장소에 흩어져 있습니다. 마크 지역 버전을 여기에 게시했습니다 : groups.google.com/d/msg/…
— Jon Harrop

1
스레드 안전과 안전하지 않은 결과가 있습니다.
— Jon Harrop

1
@Mehrdad : "이러한 잠재적 오류 원인을 제거 했습니까?" 예. OCaml에는 이스케이프 분석과 같은 최적화가없는 매우 간단한 컴파일 모델이 있습니다. 클로저에 대한 OCaml의 표현은 실제로 C ++ 솔루션보다 실질적으로 느리므로 C ++ List.filter처럼 사용자 정의 를 사용해야합니다 . 그러나 일부 RC 작업을 생략 할 수 있다는 것은 확실합니다. 그러나 야생에서 볼 수있는 가장 큰 문제는 사람들이 대규모 산업 코드 기반에서 직접 이러한 최적화를 수행 할 시간이 없다는 것입니다.
— Jon Harrop

2
네 그럼요. 코드를 작성하는 데 추가 노력을 기울이지 않아도 C ++의 병목 현상은 아닙니다. 코드를 유지 관리하는 것입니다. 이러한 종류의 부수적 인 복잡성으로 코드를 유지 관리하는 것은 악몽입니다. 대부분의 산업 코드 기반은 수백만 줄의 코드입니다. 당신은 그걸 다루고 싶지 않습니다. 사람들이 shared_ptr동시성 버그를 수정하기 위해 모든 것을 변환하는 것을 보았습니다 . 코드는 훨씬 느리지 만 이제는 작동합니다.
— Jon Harrop

-1

이러한 예에는 반드시 수동 메모리 할당 체계가 잘못되어 있습니다.

최고의 가비지 수집기를 가정하십시오 GC. 내부적으로 메모리를 할당하고 해제 할 수있는 메모리를 결정하는 방법과 최종적으로 해제 할 수있는 방법이 있습니다. 이들 모두는 모두보다 시간이 덜 걸립니다 GC. 시간이 다른 방법에 사용 GC됩니다.

이제 동일한 할당과 같은기구를 사용하는 수동 할당을 고려 GC하고, free()통화 바로 옆 메모리를 설정하는 방법과 동일한 방법에 의해 해제되는이 GC. 스캔 단계가 없으며 다른 방법도 없습니다. 시간이 덜 걸립니다.


2
가비지 콜렉터는 종종 메모리를 유용한 상태로 두지 않고도 많은 오브젝트를 해제 할 수 있습니다. 특정 기준에 맞는 모든 항목을 배열 목록에서 제거하는 작업을 고려하십시오. N- 항목 목록에서 단일 항목을 제거하는 것은 O (N)입니다. N 목록에서 M 항목을 한 번에 하나씩 제거하면 O (M * N)입니다. 그러나 목록을 한 번에 통과하여 기준을 충족하는 모든 항목을 제거하는 것은 O (1)입니다.
— supercat

@supercat : 배치도 free수집 할 수 있습니다. (물론 목록 순회 자체로 인해 기준을 충족하는 모든 항목을 제거하는 것은 여전히 ​​O (N)입니다)
— MSalters

기준을 충족하는 모든 항목을 제거하는 단계이며 , 적어도 O (N). 당신은 올바른있어 free각 메모리 항목과 연관된 플래그가 있다면 GC는 여전히 상황에서 앞으로 나올 수 있지만, 일괄 수집 모드에서 작동 할 수있다. 하나의 N 사물 중에서 L 개의 구별되는 항목을 식별하는 M 참조가있는 경우, 참조가 존재하지 않는 모든 참조를 제거하고 나머지를 통합하는 시간은 O (N)이 아니라 O (M)입니다. 사용 가능한 M 공간이 더 있으면 스케일링 상수가 매우 작을 수 있습니다. 또한, 비 스캐닝 GC 시스템의 소형화는 ... 필요
— supercat

@ supercat : 글쎄, 첫 번째 주석 상태에서 마지막 문장으로 O (1)이 아닙니다.
— MSalters

1
@MSalters : "그리고 결정 론적 체계가 보육원을 갖지 못하게하는 것은 무엇입니까?" 아무것도. OCaml의 추적 가비지 수집기는 결정 론적이며 보육원을 사용합니다. 그러나 그것은 "수동적"이 아니며 "결정적"이라는 단어를 잘못 사용하고 있다고 생각합니다.
— Jon Harrop
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.