문제

Python은 참조 카운트 방법을 사용하여 객체 수명을 처리합니다.따라서 더 이상 사용되지 않는 개체는 즉시 폐기됩니다.

하지만 Java에서는 GC(garbage collection)가 특정 시점에 더 이상 사용되지 않는 객체를 파괴합니다.

Java가 이 전략을 선택하는 이유는 무엇이며 이 전략의 이점은 무엇입니까?

이것이 Python 접근 방식보다 낫습니까?

도움이 되었습니까?

해결책

참조 카운팅을 사용하면 단점이 있습니다.가장 많이 언급되는 것 중 하나는 순환 참조입니다.A가 B를 참조하고, B가 C를 참조하고, C가 B를 참조한다고 가정합니다.A가 B에 대한 참조를 삭제하더라도 B와 C 모두 여전히 참조 카운트가 1이 되며 기존 참조 카운팅으로는 삭제되지 않습니다.CPython(참조 계산은 Python 자체의 일부가 아니라 C 구현의 일부)은 주기적으로 실행되는 별도의 가비지 수집 루틴을 사용하여 순환 참조를 포착합니다.

또 다른 단점:참조 카운팅으로 인해 실행 속도가 느려질 수 있습니다.객체가 참조 및 역참조될 때마다 인터프리터/VM은 개수가 0으로 감소했는지 확인해야 합니다(그러면 할당을 취소해야 합니다).가비지 수집에서는 이 작업을 수행할 필요가 없습니다.

또한 가비지 수집은 별도의 스레드에서 수행할 수 있습니다(다소 까다로울 수 있음).RAM이 많은 시스템과 메모리를 느리게 사용하는 프로세스의 경우 GC를 전혀 수행하고 싶지 않을 수도 있습니다!참조 카운팅은 성능 측면에서 약간의 단점이 될 것입니다 ...

다른 팁

실제로 참조 계산과 Sun JVM에서 사용하는 전략은 모두 다른 유형의 가비지 수집 알고리즘입니다.

죽은 개체를 추적하는 데는 두 가지 광범위한 접근 방식이 있습니다.추적 및 참조 카운팅.추적에서 GC는 스택 참조와 같은 "루트"에서 시작하고 도달 가능한 모든(라이브) 개체를 추적합니다.도달할 수 없는 모든 것은 죽은 것으로 간주됩니다.참조 카운팅에서는 참조가 수정될 때마다 관련된 객체의 카운트가 업데이트됩니다.참조 횟수가 0으로 설정된 모든 개체는 죽은 것으로 간주됩니다.

기본적으로 모든 GC 구현에는 장단점이 있지만 추적은 일반적으로 높은 처리량에 좋습니다(예:빠르지만 일시정지 시간이 더 깁니다(UI나 프로그램이 정지될 수 있는 간격이 더 큼).참조 카운팅은 더 작은 청크에서 작동할 수 있지만 전체적으로 속도가 느려집니다.이는 정지 현상이 줄어들지만 전반적인 성능이 저하될 수 있음을 의미합니다.

또한 참조 카운팅 GC에는 참조 카운트만으로는 포착할 수 없는 주기의 모든 개체를 정리하기 위한 주기 감지기가 필요합니다.Perl 5에는 GC 구현에 주기 감지기가 없었으며 주기적인 메모리가 누출될 수 있었습니다.

두 가지 측면(낮은 일시 중지 시간, 높은 처리량)을 최대한 활용하기 위한 연구도 수행되었습니다.http://cs.anu.edu.au/~Steve.Blackburn/pubs/papers/urc-oopsla-2003.pdf

Darren Thomas가 좋은 답변을 제공합니다.그러나 Java와 Python 접근 방식의 한 가지 큰 차이점은 일반적인 경우(순환 참조 없음)의 참조 계산을 사용하면 불확실한 나중에가 아니라 즉시 정리된다는 것입니다.

예를 들어 CPython에서 다음과 같이 엉성하고 이식 불가능한 코드를 작성할 수 있습니다.

def parse_some_attrs(fname):
    return open(fname).read().split("~~~")[2:4]

열린 파일에 대한 참조가 사라지자마자 파일이 가비지 수집되고 파일 설명자가 해제되기 때문에 내가 연 해당 파일에 대한 파일 설명자는 즉시 정리됩니다.물론 Jython이나 IronPython 또는 PyPy를 실행하는 경우 가비지 수집기가 반드시 훨씬 나중에 실행될 필요는 없습니다.아마도 파일 설명자가 먼저 부족해지면 프로그램이 충돌할 수도 있습니다.

따라서 다음과 같은 코드를 작성해야 합니다.

def parse_some_attrs(fname):
    with open(fname) as f:
        return f.read().split("~~~")[2:4]

그러나 때때로 사람들은 참조 계산에 의존하여 리소스를 확보하기를 좋아합니다. 왜냐하면 때때로 코드가 조금 더 짧아질 수 있기 때문입니다.

나는 최고의 가비지 수집기가 최고의 성능을 가진 것이라고 말하고 싶습니다. 현재는 별도의 스레드에서 실행될 수 있고 이러한 모든 미친 최적화 기능을 갖춘 Java 스타일의 세대별 가비지 수집기인 것 같습니다.코드 작성 방법의 차이는 무시할 수 있고 이상적으로는 존재하지 않아야 합니다.

내 생각에 기사는 "자바 이론 및 실제:가비지 컬렉션의 간략한 역사" IBM의 질문이 귀하가 갖고 있는 몇 가지 질문을 설명하는 데 도움이 될 것입니다.

메모리가 충분하면 가비지 수집이 참조 계산보다 더 빠릅니다(시간 효율적).예를 들어 복사 gc는 "라이브" 개체를 탐색하여 새 공간에 복사하고 전체 메모리 영역을 표시하여 한 단계에서 모든 "죽은" 개체를 회수할 수 있습니다.이는 매우 효율적이며, 만약에 당신은 충분한 기억력을 가지고 있습니다.세대별 컬렉션은 "대부분의 개체가 어릴 때 죽는다"는 지식을 사용합니다.종종 개체의 몇 퍼센트만 복사하면 됩니다.

[이것이 gc가 malloc/free보다 빠른 이유이기도 합니다.]

참조 카운팅은 가비지 컬렉션보다 훨씬 더 공간 효율적입니다. 메모리에 접근할 수 없는 순간에 메모리를 회수하기 때문입니다.이는 객체에 종료자를 연결하려는 경우 유용합니다(예:File 객체에 접근할 수 없게 되면 파일을 닫습니다.)참조 카운팅 시스템은 메모리의 몇 퍼센트만 사용 가능하더라도 작동할 수 있습니다.그러나 각 포인터 할당 시 카운터를 늘리거나 줄여야 하는 관리 비용에는 많은 시간이 소요되며 주기를 회수하려면 일종의 가비지 수집이 여전히 필요합니다.

따라서 절충안은 분명합니다.메모리가 제한된 환경에서 작업해야 하거나 정확한 종료자가 필요한 경우 참조 계산을 사용하세요.메모리가 충분하고 속도가 필요한 경우 가비지 수집을 사용하세요.

Java 추적 GC의 가장 큰 단점 중 하나는 전체 GC를 수행하기 위해 때때로 "세계를 중지"하고 상대적으로 오랜 시간 동안 애플리케이션을 정지시킨다는 것입니다.힙이 크고 개체 트리가 복잡하면 몇 초 동안 정지됩니다.또한 각각의 전체 GC는 전체 개체 트리를 계속해서 다시 방문하는데 이는 아마도 상당히 비효율적일 것입니다.Java가 GC를 수행하는 방식의 또 다른 단점은 원하는 힙 크기를 jvm에 알려야 한다는 것입니다(기본값이 충분하지 않은 경우).JVM은 힙에 너무 많은 쓰레기가 쌓일 때 GC 프로세스를 트리거하는 여러 임계값을 해당 값에서 파생합니다.

나는 이것이 실제로 iOS의 부드러움(ObjectiveC 기반, RC 사용)과 비교하여 가장 비싼 휴대폰에서도 Android(Java 기반)의 불안정한 느낌의 주요 원인이라고 추정합니다.

RC 메모리 관리를 활성화하는 jvm 옵션을 보고 싶고, 메모리가 더 이상 남아 있지 않을 때 최후의 수단으로만 GC를 실행하도록 유지하고 싶습니다.

최신 Sun Java VM에는 실제로 조정할 수 있는 여러 GC 알고리즘이 있습니다.Java VM 사양에서는 다양한 VM에 대해 서로 다른(및 여러) GC 알고리즘을 허용하기 위해 실제 GC 동작 지정을 의도적으로 생략했습니다.

예를 들어, 기본 Sun Java VM GC 동작의 "세계를 멈추는" 접근 방식을 싫어하는 모든 사람들을 위해 다음과 같은 VM이 있습니다. IBM의 웹스피어 리얼타임 실시간 애플리케이션을 Java에서 실행할 수 있습니다.

Java VM 사양은 공개적으로 사용 가능하므로 (이론적으로) CPython의 GC 알고리즘을 사용하는 Java VM을 구현하는 것을 막을 수 있는 방법은 없습니다.

다중 스레드 환경에서는 참조 카운팅을 효율적으로 수행하기가 특히 어렵습니다.하드웨어 지원 트랜잭션이나 이와 유사한 (현재) 특이한 원자 명령을 사용하지 않고 어떻게 이 작업을 시작할 수 있는지 모르겠습니다.

참조 카운팅은 구현하기 쉽습니다.JVM은 경쟁 구현에 많은 돈을 투자했기 때문에 매우 어려운 문제에 대한 매우 좋은 솔루션을 구현한다는 것은 놀라운 일이 아닙니다.그러나 JVM에서 선호하는 언어를 대상으로 지정하는 것이 점점 쉬워지고 있습니다.

게임 후반부에서는 Python에서 RC를 사용하는 중요한 이유 중 하나가 단순성이라고 생각합니다.이것 좀 봐 Alex Martelli의 이메일, 예를 들어.

(파이썬 목록에서 이메일 날짜가 2005년 10월 13일인 Google 캐시 외부 링크를 찾을 수 없습니다.)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top