문제

내 프로그래밍 언어에 포함할 기능을 찾기 위해 가비지 수집에 대한 내용을 읽다가 "약한 포인터"를 발견했습니다.에서 여기:

약한 포인터는 약한 포인터의 참조가 쓰레기 수집을 방해하지 않으며 약한 포인터가 사용하기 전에 유효성을 점검해야한다는 점을 제외하고는 포인터와 같습니다.

약한 포인터는 쓰레기 수집기와 상호 작용합니다. 왜냐하면 그들이 참조하는 메모리는 실제로 유효 할 수 있지만 약한 포인터가 생성 될 때와는 다른 물체를 포함하기 때문입니다.따라서 쓰레기 수집기가 메모리를 재활용 할 때마다, 그것을 언급하는 약한 포인터가 있는지 확인하고 유효하지 않은 것으로 표시해야합니다 (이 순진한 방식으로 구현 될 필요는 없습니다).

나는 약한 포인터에 대해 들어본 적이 없습니다.나는 내 언어로 많은 기능을 지원하고 싶지만 이 경우 이것이 유용할 수 있는 경우는 평생 생각할 수 없습니다.약한 포인터는 무엇을 위해 사용됩니까?

도움이 되었습니까?

해결책

일반적인 사용 사례는 추가 객체 속성을 저장하는 것입니다.고정된 구성원 집합이 있는 클래스가 있고 외부에서 더 많은 구성원을 추가하려고 한다고 가정해 보겠습니다.따라서 키가 약한 참조인 사전 개체 -> 속성을 ​​만듭니다.그런 다음 사전은 키가 가비지 수집되는 것을 방지하지 않습니다.객체를 제거하면 WeakKeyDictionary의 값도 제거되어야 합니다(예:콜백을 통해).

다른 팁

정말 큰 것입니다 캐싱. 캐시가 어떻게 작동하는지 생각해 봅시다.

캐시 뒤의 아이디어는 메모리 압력이 너무 커질 때까지 객체를 메모리에 저장하는 것입니다. 따라서 캐시 저장소 객체는 이러한 객체를 어떻게 든 유지해야합니다. 약한 참조를 통해 그것들을 붙잡고, 쓰레기 수집기가 메모리가 낮기 때문에 소비 할 물건을 찾을 때, 약한 참조로만 언급 된 항목은 쓰레기 수집 후보로 나타납니다. 현재 다른 코드에서 사용중인 캐시의 항목은 하드 참조가 여전히 활성화되므로 해당 항목은 쓰레기 수집으로부터 보호됩니다.

대부분의 상황에서는 자신의 캐싱 메커니즘을 굴리지 않지만 캐시를 사용하는 것이 일반적입니다. 캐시의 객체를 나타내는 속성을 원하고 해당 속성이 오랫동안 범위를 유지하고 싶다고 가정 해 봅시다. 당신은 할 것입니다 선호하다 캐시에서 객체를 가져 오려면 사용할 수없는 경우 지속적인 스토리지에서 가져올 수 있습니다. 또한 압력이 너무 높아지면 특정 물체가 메모리에 머무르도록 강요하고 싶지 않습니다. 그래서 당신은 그 객체에 대한 약한 참조를 사용할 수 있습니다. 사용 가능한 경우 또한 캐시에서 떨어질 수 있습니다.

언어의 쓰레기 수집가가 원형 데이터 구조를 수집 할 수없는 경우 약한 참조를 사용하여이를 가능하게 할 수 있습니다. 일반적으로 서로 참조하는 두 개의 객체가 있지만 다른 외부 객체 가이 두 개체에 대한 참조가없는 경우 쓰레기 수집 후보가됩니다. 그러나 순진한 쓰레기 수집가는 서로에 대한 언급이 포함되어 있기 때문에 수집하지 않을 것입니다.

이것을 고치기 위해, 당신은 그것을 두 번째 객체에 대해 강력한 참조로 만들지 만 두 번째 객체는 첫 번째 객체에 대해 약한 참조를 가지고 있습니다. 그런 다음 첫 번째 객체에 대한 마지막 외부 참조가 사라지면 첫 번째 물체는 쓰레기 수집 후보가되고 그 후 얼마 지나지 않아 두 번째 참조가 약하기 때문입니다.

또 다른 예는 ... 캐싱이 아니라 비슷합니다. I/O 라이브러리가 파일 디스크립터를 감싸고 파일에 대한 액세스를 허용하는 객체를 제공한다고 가정합니다. 객체가 수집되면 파일 디스크립터가 닫힙니다. 현재 열린 모든 파일을 나열 할 수 있기를 원합니다. 이 목록에 강한 포인터를 사용하면 파일이 닫히지 않습니다.

캐시 된 객체 목록을 유지하려면 사용하지만 객체의 "실제"소유자가 완료되면 객체가 쓰레기를 수집하는 것을 막지는 않습니다.

웹 브라우저에는 브라우저가 다른 곳에로드하고 히스토리/디스크 캐시에 저장 한 이미지 객체에 대한 참조를 유지하는 히스토리 개체가있을 수 있습니다. 웹 브라우저는 해당 이미지 중 하나를 만료 할 수 있지만 (사용자가 캐시를 지우고 캐시 타임 아웃이 경과하는 등) 페이지에는 여전히 참조/포인터가 있습니다. 페이지가 약한 기준/포인터를 사용하면 물체가 예상대로 사라지고 메모리는 쓰레기를 수집합니다.

참조가 약한 한 가지 중요한 이유 중 하나는 객체가 정보 또는 이벤트를 하나 이상의 청취자에게 연결하는 파이프 라인 역할을 할 가능성을 다루기 때문입니다. 청취자가 없으면 파이프 라인에 정보를 계속 전송할 이유가 없습니다.

예를 들어 열거하는 동안 업데이트 할 수있는 열거 가능한 컬렉션을 고려하십시오. 컬렉션은 활성 열거 자에게 변경되었음을 알리면 해당 열거자가 그에 따라 스스로 조정할 수 있습니다. 일부 열거자가 제작자에 의해 버려지지만 컬렉션이 강력한 참조를 보유하고 있다면, 해당 열거자는 컬렉션이 존재하는 한 계속해서 존재할 것입니다 (및 프로세스 업데이트 알림). 컬렉션 자체가 응용 프로그램의 수명 동안 존재하는 경우, 해당 열거자는 효과적으로 영구적 인 메모리 누출이됩니다.

컬렉션이 열거 자에 대한 약한 참조를 보유하고 있다면이 문제는 크게 해결 될 수 있습니다. 열거자가 포기되면 컬렉션이 여전히 약한 참조를 보유하더라도 쓰레기 수거에 적합합니다. 다음에 컬렉션이 변경되면 약한 참조 목록을 살펴보고 여전히 유효한 업데이트를 보내고, 그렇지 않은 목록에서 업데이트를 제거 할 수 있습니다.

일부 추가 객체와 함께 결승전기를 사용하여 약한 참조의 많은 영향을 달성 할 수 있으며, 약한 참조를 사용하는 것보다 이러한 구현을 더 효율적으로 만들 수 있지만 많은 함정이 있으며 버그를 피하기가 어렵습니다. 약점을 사용하여 올바른 접근 방식을 만드는 것이 훨씬 쉽습니다. 접근 방식은 최적으로 효율적이지 않지만 심하게 실패하지는 않습니다.

약한 포인터는 포인터가 가리키는 개체에 대한 "생명 유지"의 형태가 되는 것을 방지합니다.

Viewport 클래스와 2개의 UI 클래스, 그리고 많은 Widget 클래스가 있다고 가정해 보겠습니다.UI가 생성하는 위젯의 수명을 제어하기를 원하므로 UI는 제어하는 ​​모든 위젯에 대해 SharedPtr을 유지합니다.UI 객체가 살아 있는 한, 참조하는 위젯 중 어떤 것도 가비지 수집되지 않습니다(SharedPtr 덕분에).

그러나 뷰포트는 실제로 그리기를 수행하는 클래스이므로 UI가 위젯을 그릴 수 있도록 뷰포트에 위젯에 대한 포인터를 전달해야 합니다.어떤 이유로든 활성 UI 클래스를 다른 클래스로 변경하려고 합니다.UI가 Viewport WeakPtrs를 전달한 시나리오와 SharedPtrs(위젯을 가리키는)를 전달한 시나리오의 두 가지 시나리오를 고려해 보겠습니다.

모든 위젯을 WeakPointer로 뷰포트에 전달한 경우 UI 클래스가 삭제되자마자 위젯에 대한 SharedPointer가 더 이상 존재하지 않으므로 가비지 수집되며 객체에 대한 뷰포트의 참조는 " 생명 유지"는 UI가 생성한 위젯은 물론 더 이상 해당 UI를 사용하지도 않기 때문에 정확히 원하는 것입니다.

이제 뷰포트에 SharedPointer를 전달하고 UI를 삭제하면 위젯이 가비지 수집되지 않는다고 가정해 보세요.왜?아직 살아있는 뷰포트에는 위젯에 대한 SharedPtr로 가득 찬 배열(벡터 또는 목록 등)이 있기 때문입니다.다른 UI 개체의 위젯을 제어하는 ​​UI를 삭제했음에도 불구하고 뷰포트는 사실상 "생명 유지"의 한 형태가 되었습니다.

일반적으로 언어/시스템/프레임워크는 메모리 어딘가에 "강력한" 참조가 없는 한 무엇이든 가비지 수집합니다.모든 것이 모든 것에 대한 강력한 참조를 가지고 있다면 어떤 것도 가비지 수집되지 않을 것이라고 상상해 보십시오!때로는 그런 행동을 원할 때도 있고 그렇지 않을 때도 있습니다.WeakPtr을 사용하고 개체를 가리키는 Shared/StrongPtr이 남아 있지 않은 경우(WeakPtr만) 개체는 WeakPtr 참조에도 불구하고 가비지 수집되며 WeakPtr은 NULL로 설정되거나 삭제되거나 무엇).

다시 말하지만, WeakPtr을 사용하면 기본적으로 제공하는 개체도 데이터에 액세스할 수 있도록 허용하지만 WeakPtr은 SharedPtr처럼 가리키는 개체의 가비지 수집을 방지하지 않습니다.sharedptr을 생각할 때 "생명 지원", 약점, "생명 지원"은 없습니다. 물체가 생명 지원이 제로가 될 때까지는 (일반적으로) 쓰레기 수집이 발생하지 않습니다.

예를 들어, 약한 참조는 캐싱 시나리오에서 사용할 수 있습니다. 약한 참조를 통해 데이터에 액세스 할 수 있지만, 오랫동안 데이터에 액세스하지 않거나 메모리 압력이 높으면 GC는 해방할 수 있습니다.

쓰레기 수집의 이유는 전혀 메모리 관리가 프로그래머를 완전히 통제하는 C와 같은 언어에서, 특히 객체 소유권이 특히 스레드 사이 또는 더 어려워지면 메모리 공유, 메모리 누출을 피하고, 메모리 누출 및 매달려있는 포인터는 매우 어려워 질 수 있습니다. 그것이 충분히 어렵지 않다면, 당신은 또한 한 번에 메모리에 맞는 것보다 더 많은 객체에 액세스해야 할 필요성을 처리해야합니다. 메모리에있을 수 있습니다.

따라서 일부 언어 (예 : Perl, LISP, Java)는 "물체"를 사용하여 "멈출 수있는 메커니즘을 제공하며 쓰레기 수집기는 결국 이것을 발견하고 객체에 사용되는 메모리를 자유롭게합니다. 프로그래머가 잘못 될 수있는 모든 방법에 대해 걱정하지 않고도 올바르게 수행합니다 (프로그래머가 이것을 망칠 수있는 많은 방법이 있지만).

개념적으로 객체 값을 계산하는 데 걸리는 시간에 객체에 액세스하는 횟수를 개념적으로 곱한 경우, 객체를 쉽게 사용할 수없는 비용으로 또는 메모리 주변의 큰 물체는 여러 개의 작은 물체를 주위에 유지하지 못하면 객체를 세 가지 범주로 분류 할 수 있습니다.

일부 대상은 매우 중요하여 자신의 존재를 명시 적으로 관리하고자합니다. 그들은 쓰레기 수집가가 관리하지 않거나 명시 적으로 해제 될 때까지 수집해서는 안됩니다. 일부 물체는 계산하기가 싸고, 작고, 자주 접근하지 않거나, 언제든지 쓰레기를 수집 할 수있는 비슷한 특성을 가지고 있습니다.

세 번째 클래스, 재 계산 비용이 많이 들지만 재 계산 될 수있는 물체는 다소 자주 액세스하고 (아마도 짧은 시간 동안) 큰 크기가 많으며, 세 번째 클래스입니다. 다시 재사용 될 수 있기 때문에 가능한 한 오랫동안 메모리에 유지하고 싶지만 중요한 객체에 필요한 메모리가 부족하지 않기를 원합니다. 이들은 약한 참고 자료 후보입니다.

중요한 자원과 충돌하지 않으면 이러한 물체를 가능한 한 오래 유지하기를 원하지만 필요할 때 다시 계산할 수 있으므로 중요한 자원에 메모리가 필요한 경우 삭제해야합니다. 이들은 모자 약한 포인터입니다.

이것의 예는 사진 일 수 있습니다. 수천 장의 사진이 표시된 사진 웹 페이지가 있다고 가정 해 봅시다. 배치 할 사진 수를 알아야하며 목록을 얻으려면 데이터베이스 쿼리를 수행해야 할 수도 있습니다. 수천 가지 항목 목록을 보유하는 메모리는 아마도 매우 작을 것입니다. 한 번 쿼리를하고 주위에 보관하고 싶습니다.

그러나 웹 페이지의 창에 한 번에 수십 장의 사진 만 물리적으로 보여줄 수 있습니다. 사용자가 볼 수없는 사진의 비트를 가져올 필요는 없습니다. 사용자가 페이지를 스크롤하면 볼 수있는 그림의 실제 비트를 수집합니다. 그 사진들은 그들을 보여주기 위해 많은 메가 바이트가 필요할 수 있습니다. 사용자가 몇 개의 스크롤 위치를 앞뒤로 스크롤하는 경우, 해당 메가 바이트를 반복해서 리치하지 않아도됩니다. 그러나 모든 사진을 항상 기억 상태로 유지할 수는 없습니다. 그래서 당신은 약한 포인터를 사용합니다.

사용자가 몇 장의 사진을 반복해서 보면 캐시에 머무를 수 있으며 리치 할 필요가 없습니다. 그러나 충분히 스크롤하면 눈에 보이는 사진을 가져올 수 있도록 메모리를 확보해야합니다. 약한 참조를 사용하면 참조를 사용하기 직전에 참조를 확인합니다. 여전히 유효한 경우 사용합니다. 그렇지 않은 경우, 당신은 그것을 얻기 위해 값 비싼 계산 (페치)을 만듭니다.

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