내가 아는 유일한 것은 약 PhantomReference
이다
get()
메서드 를 사용 하면 항상null
개체가 아닌 반환됩니다 . 그것의 용도는 무엇입니까?- 를 사용하여 메서드
PhantomReference
에서 개체를 부활시킬 수 없음을 확인합니다finalize
.
그러나이 개념 / 클래스의 용도는 무엇입니까?
프로젝트에서 이것을 사용한 적이 있습니까? 아니면 우리가 이것을 사용해야 할 예가 있습니까?
내가 아는 유일한 것은 약 PhantomReference
이다
get()
메서드 를 사용 하면 항상 null
개체가 아닌 반환됩니다 . 그것의 용도는 무엇입니까?PhantomReference
에서 개체를 부활시킬 수 없음을 확인합니다 finalize
.그러나이 개념 / 클래스의 용도는 무엇입니까?
프로젝트에서 이것을 사용한 적이 있습니까? 아니면 우리가 이것을 사용해야 할 예가 있습니까?
FakeReference
또는 NonReference
.
답변:
객체 생성 및 파괴를 모니터링하기 위해 단순하고 매우 특수한 종류의 메모리 프로파일 러PhantomReference
에서 s를 사용했습니다 . 파괴를 추적하기 위해 그것들이 필요했습니다. 그러나 접근 방식은 오래되었습니다. (J2SE 1.4를 대상으로 2004 년에 작성되었습니다.) 전문 프로파일 링 도구는 훨씬 더 강력하고 안정적이며 JMX 또는 에이전트 및 JVMTI와 같은 최신 Java 5 기능도 사용할 수 있습니다.
PhantomReference
s (항상 참조 대기열과 함께 사용됨) finalize
는 몇 가지 문제 가있는 것보다 우수 하므로 피해야합니다. 주로 개체에 다시 도달 할 수 있도록합니다. 이것은 파이널 라이저 가디언 관용구 (-> 'Effective Java'에서 더 읽어보기)로 피할 수 있습니다. 그래서 그들은 또한 새로운 finalize 입니다.
또한 PhantomReference
s
객체가 메모리에서 제거 된시기를 정확히 확인할 수 있습니다. 사실 그들은 그것을 결정하는 유일한 방법입니다. 이것은 일반적으로 그다지 유용하지 않지만 큰 이미지 조작과 같은 특정 상황에서 유용 할 수 있습니다. 이미지가 가비지 수집되어야 함을 확실히 알고 있다면 다음 이미지를로드하기 전에 실제로 될 때까지 기다릴 수 있습니다. , 따라서 두려운 OutOfMemoryError의 가능성을 줄입니다. ( enicholas 에서 인용 .)
그리고 psd 가 먼저 썼 듯이 Roedy Green은 참고 문헌에 대한 좋은 요약을 가지고 있습니다.
Java Glossary 의 일반적인 요약 표 설명 입니다.
와 코스 일치의 어떤 PhantomReference 문서 :
수집기가 참조 대상을 회수 할 수 있다고 결정한 후 대기열에 추가되는 팬텀 참조 개체입니다. Phantom 참조는 Java 종료 메커니즘에서 가능한 것보다 더 유연한 방식으로 사전 정리 조치를 스케줄링하는 데 가장 자주 사용됩니다.
그리고 마지막으로, 모든 세부 사항 ( 좋은 읽기 ) : Java Reference Objects (또는 How I Learned to Stop Worrying and Love OutOfMemoryError) .
즐거운 코딩입니다. (그러나 질문에 답하기 위해 WeakReferences 만 사용했습니다.)
팬텀 레퍼런스 사용법에 대한 훌륭한 설명 :
팬텀 참조는 객체가 메모리에서 제거되었음을 알 수있는 안전한 방법입니다. 예를 들어, 큰 이미지를 처리하는 애플리케이션을 고려하십시오. 큰 이미지가 이미 가비지 수집 준비가 된 메모리에있을 때 큰 이미지를 메모리에로드한다고 가정합니다. 이 경우 새 이미지를로드하기 전에 이전 이미지가 수집 될 때까지 기다립니다. 여기에서 가상 참조는 유연하고 안전하게 선택할 수있는 옵션입니다. 이전 이미지 객체가 완료되면 이전 이미지의 참조가 ReferenceQueue에 추가됩니다. 해당 참조를받은 후 새 이미지를 메모리에로드 할 수 있습니다.
이것은 JAVA 9에서 더 이상 사용되지 않아야합니다! 대신
사용하십시오 java.util.Cleaner
! (또는 sun.misc.Cleaner
이전 JRE에서)
원본 게시물 :
나는 PhantomReferences의 사용이 종료 자 메서드와 거의 같은 양의 함정을 가지고 있음을 발견했습니다 (하지만 제대로 된 후에는 문제가 적습니다). Java 8 용 작은 솔루션 (PhantomReferences를 사용하기위한 매우 작은 프레임 워크)을 작성했습니다. 객체가 제거 된 후 실행할 콜백으로 람다 식을 사용할 수 있습니다. 닫아야하는 내부 리소스에 대한 콜백을 등록 할 수 있습니다. 이것으로 훨씬 더 실용적이기 때문에 나를 위해 작동하는 솔루션을 찾았습니다.
https://github.com/claudemartin/java-cleanup
다음은 콜백 등록 방법을 보여주는 간단한 예입니다.
class Foo implements Cleanup {
//...
public Foo() {
//...
this.registerCleanup((value) -> {
try {
// 'value' is 'this.resource'
value.close();
} catch (Exception e) {
logger.warning("closing resource failed", e);
}
}, this.resource);
}
그리고 위와 거의 동일한 자동 닫기 방법이 있습니다.
this.registerAutoClose(this.resource);
질문에 답하려면 :
[그런 다음 그것의 사용은 무엇입니까]
존재하지 않는 것을 정리할 수 없습니다. 그러나 여전히 존재하고 제거 할 수 있도록 정리해야하는 리소스가있을 수 있습니다.
그러나이 개념 / 클래스의 용도는 무엇입니까?
디버깅 / 로깅 이외의 다른 효과로 반드시 수행 할 필요는 없습니다. 아니면 통계를 위해. GC의 알림 서비스처럼 보입니다. 개체가 제거되면 관련성이없는 집계 데이터를 제거하는 데 사용할 수도 있습니다 (하지만 더 나은 솔루션이있을 수 있음). 예제에서는 종종 데이터베이스 연결을 닫아야한다고 언급하지만 트랜잭션으로 작업 할 수 없기 때문에 이것이 얼마나 좋은 생각인지 모르겠습니다. 애플리케이션 프레임 워크는이를위한 훨씬 더 나은 솔루션을 제공합니다.
당신의 프로젝트에서 이것을 사용한 적이 있습니까, 아니면 우리가 이것을 사용해야 할 예가 있습니까? 아니면이 개념이 인터뷰 관점에서 만들어진 것입니까?)
주로 로깅에만 사용합니다. 따라서 제거 된 요소를 추적하고 GC가 어떻게 작동하고 조정할 수 있는지 확인할 수 있습니다. 나는 이런 식으로 중요한 코드를 실행하지 않을 것입니다. 무언가를 닫아야하는 경우 try-with-resource-statement에서 수행해야합니다. 그리고 메모리 누수가 없는지 확인하기 위해 단위 테스트에서 사용합니다. jontejj와 같은 방식으로합니다. 하지만 내 솔루션은 좀 더 일반적입니다.
단위 테스트에서 PhantomReference를 사용하여 테스트중인 코드가 일부 개체에 대한 비 필수 참조를 유지하지 않았는지 확인했습니다. ( 원래 코드 )
import static com.google.common.base.Preconditions.checkNotNull;
import static org.fest.assertions.Assertions.assertThat;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import com.google.common.testing.GcFinalization;
/**
* Helps to test for memory leaks
*/
public final class MemoryTester
{
private MemoryTester()
{
}
/**
* A simple {@link PhantomReference} that can be used to assert that all references to it is
* gone.
*/
public static final class FinalizationAwareObject extends PhantomReference<Object>
{
private final WeakReference<Object> weakReference;
private FinalizationAwareObject(Object referent, ReferenceQueue<Object> referenceQueue)
{
super(checkNotNull(referent), referenceQueue);
weakReference = new WeakReference<Object>(referent, referenceQueue);
}
/**
* Runs a full {@link System#gc() GC} and asserts that the reference has been released
* afterwards
*/
public void assertThatNoMoreReferencesToReferentIsKept()
{
String leakedObjectDescription = String.valueOf(weakReference.get());
GcFinalization.awaitFullGc();
assertThat(isEnqueued()).as("Object: " + leakedObjectDescription + " was leaked").isTrue();
}
}
/**
* Creates a {@link FinalizationAwareObject} that will know if {@code referenceToKeepTrackOff}
* has been garbage collected. Call
* {@link FinalizationAwareObject#assertThatNoMoreReferencesToReferentIsKept()} when you expect
* all references to {@code referenceToKeepTrackOff} be gone.
*/
public static FinalizationAwareObject createFinalizationAwareObject(Object referenceToKeepTrackOff)
{
return new FinalizationAwareObject(referenceToKeepTrackOff, new ReferenceQueue<Object>());
}
}
그리고 테스트 :
@Test
public void testThatHoldingOnToAnObjectIsTreatedAsALeak() throws Exception
{
Object holdMeTight = new String("Hold-me-tight");
FinalizationAwareObject finalizationAwareObject = MemoryTester.createFinalizationAwareObject(holdMeTight);
try
{
finalizationAwareObject.assertThatNoMoreReferencesToReferentIsKept();
fail("holdMeTight was held but memory leak tester did not discover it");
}
catch(AssertionError expected)
{
assertThat(expected).hasMessage("[Object: Hold-me-tight was leaked] expected:<[tru]e> but was:<[fals]e>");
}
}
더 적절한 WeakReference
곳에 사용 하는 것이 일반적 PhantomReference
입니다. 이렇게하면 WeakReference
가비지 수집기에서 a 를 지우거나 대기열에 넣은 후 개체를 부활시킬 수있는 특정 문제를 방지 할 수 있습니다. 보통 사람들이 어리석은 버거를하지 않기 때문에 그 차이는 중요하지 않습니다.
방법이 작동 PhantomReference
하는 척할 수 없기 때문에 사용 은 좀 더 방해가되는 경향이 있습니다 get
. 예를 들어 Phantom[Identity]HashMap
.
weakref.get
를 반환 할 수 null
있고 나중에 obj를 반환 할 수 있습니까?
finalize
는 객체를 다시 생성하지 않습니다. 에서 WeakReference
반환 null
되어 get
대기열에 추가 된 후 객체에 다시 강력하게 도달 할 수 있습니다. / (user166390 : 참조 대상에 키가 지정된 맵에서와 마찬가지로 참조 WeakHashMap
의 식별 맵이 아닙니다.)
get () 메서드를 사용하면 항상 객체가 아닌 null을 반환합니다. [그런 다음 그것의 사용은 무엇입니까]
호출하는 데 유용한 메서드 (보다는 get()
)는 isEnqueued()
또는 referenceQueue.remove()
입니다. 이러한 메서드를 호출하여 개체의 가비지 수집의 마지막 라운드에서 발생해야하는 작업을 수행합니다.
처음에는 객체에 finalize()
메서드가 호출되어 닫는 후크도 넣을 수 있습니다. 그러나 다른 사람들이 말했듯이 정리를 수행하는 더 확실한 방법이나 가비지 수집 전후 또는 더 일반적으로 개체 수명이 끝날 때 수행해야하는 작업이있을 수 있습니다.
Jetty의 LeakDetector 클래스 PhantomReferences
에서의 또 다른 실용적인 사용을 발견했습니다 .
Jetty는 LeakDetector
클래스를 사용 하여 클라이언트 코드가 리소스를 얻었는지 여부를 감지하지만 리소스를 해제하지 않으며 LeakDetector
클래스는 PhantomReferences
이 목적을 위해를 사용합니다 .