WeakHashMap 깊이 들 어가 기
최근 작업 중 자바 util. Weak HashMap < K, V >, 그 속 의 오묘 함 을 이해 하지 못 하고 결말 을 찾 아 기록 하 다.
Java 참조 형식
우선 자바 의 네 가지 인용 유형 을 알 아야 합 니 다.
GC 는 강력 한 인용 을 회수 하지 않 습 니 다. 메모리 가 부족 하 더 라 도 그렇지 않 습 니 다. 차라리 OOM 하 겠 습 니 다.
SoftReference 의 주요 특징 은 비교적 강 한 인용 기능 을 가지 고 있다 는 것 이다.
메모리 가 부족 할 때 만 회수 하고 메모리 가 충분 할 때 는 회수 되 지 않 는 다.
또한 인용 대상 은 자바 가 OutOfmory Error 를 던 지기 전에 null 로 설정 할 수 있 도록 보장 합 니 다.
소프트 인용 사용 은 guava - cache 를 참고 할 수 있 습 니 다.
PhantomReference 대상 이 finalize 방법 을 실행 한 후 Unreachable Objects 가 됩 니 다.
그러나 아직 회수 되 지 않 았 기 때문에 이때 finalize 를 보조 하여 후기 회수 작업 을 할 수 있다.
Weak HashMap 에서 Weak 를 어떻게 실현 합 니까?
다 들 아시 다시 피 Map 은 Entry 로 데 이 터 를 저장 하고 Weak HashMap 의 세부 사항 을 살 펴 보 세 요.
Put 부분의 코드 는 다음 과 같 습 니 다.
Entry<K,V> e = tab[i];
tab[i] = new Entry<K,V>(k, value, queue, h, e);
if (++size >= threshold)
resize(tab.length * 2);
다음은 Weak HashMap 의 Entry 실현, Weak Reference 계승
private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V> {
private V value;
private final int hash;
private Entry<K,V> next;
/**
* Creates new entry.
*/
Entry(K key, V value,
ReferenceQueue<K> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
Key 를 Reference 로 처리 하기:
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
HashMap 과 비교 해 보면 Entry 는 Key 라 는 대상 을 직접 인용 하지 않 고 인용 관 계 를 부류 Weak Reference 에 넣 었 다. Weak HashMap 은 들 어 오 는 key 를 Weak Reference 로 포장 하고 Reference Queue 에 들 어 온 것 을 알 수 있다.그러나 약 한 인용의 실현 세부 사항 은 아직 명확 하지 않 으 니 이어서 파 헤 쳐 라.
키 는 어떻게 정리 합 니까?
Reference 클래스 에 static 코드 가 있 습 니 다.
static private class Lock { };
private static Lock lock = new Lock();
private static Reference pending = null;
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
}
스 레 드 의 우선 순 위 를 MAX 로 설정 합 니 다. 어떤 스 레 드 가 이렇게 높 은 권한 을 필요 로 합 니까?pending 、lock 은 모두 static 에 의 해 설명 되 었 습 니 다. lock. wait 이후 에 누가 깨 웠 는 지 인터넷 에서 검색 을 한 후에 야 JVM 이 이런 일 에 참여 했다 는 것 을 알 게 되 었 습 니 다.
통속 적 인 말로 JVM 이 한 일 을 연결 하 다. Weak HashMap 대상 에 많은 대상 의 인용 이 저장 되 어 있다 고 가정 합 니 다.JVM 은 CMS GC 를 진행 할 때 ConcurrentMarkSweetThread (CMST 로 약칭) 스 레 드 를 만들어 GC 를 진행 합 니 다. ConcurrentMarkSweetThread 스 레 드 가 생 성 되 는 동시에 SurrogateLockerThread (SLT 로 약칭) 스 레 드 를 만 들 고 시작 합 니 다. SLT 가 시작 되면 대기 단계 에 있 습 니 다.CMST 가 GC 를 시작 할 때 SLT 에 자바 계층 Reference 대상 의 전역 잠 금 을 가 져 오 라 는 메 시 지 를 보 냅 니 다: lock.JVM 은 CMS GC 가 완 료 될 때 까지 Weak HashMap 에서 회수 대상 이 속 한 Weak Reference 용기 대상 을 Reference pending 에 넣 습 니 다. 속성 중 (매번 GC 가 끝 난 후 pending 속성 은 기본적으로 null 이 되 지 않 습 니 다), 그리고 SLT 에 게 방출 을 알 리 고 notify 전역 잠 금: lock.이때 Reference Handler 스 레 드 의 run 방법 을 활성화 하여 wait 상태 에서 벗 어 나 작업 을 시작 합 니 다.Reference Handler 라 는 스 레 드 는 pending 의 모든 Weak Reference 대상 을 각자 의 줄 로 이동 합 니 다. 예 를 들 어 현재 이 Weak Reference 는 특정한 Weak HashMap 대상 에 속 하면 해당 하 는 Reference Queue 줄 에 들 어 갑 니 다 (이 줄 은 링크 구조 입 니 다).
구체 적 인 디 테 일 을 알 고 싶 으 면 openjdk 의 소스 코드 인 스 턴 스 RefKlass. cpp 를 깊이 파 헤 쳐 lock 부분 을 얻 습 니 다.
void instanceRefKlass::acquire_pending_list_lock(BasicLock *pending_list_basic_lock) {
// we may enter this with pending exception set
PRESERVE_EXCEPTION_MARK; // exceptions are never thrown, needed for TRAPS argument
Handle h_lock(THREAD, java_lang_ref_Reference::pending_list_lock());
ObjectSynchronizer::fast_enter(h_lock, pending_list_basic_lock, false, THREAD);
assert(ObjectSynchronizer::current_thread_holds_lock(
JavaThread::current(), h_lock),
"Locking should have succeeded");
if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION;
}
GC 완료 후, pending 할당, lock 방출
void instanceRefKlass::release_and_notify_pending_list_lock(
BasicLock *pending_list_basic_lock) {
// we may enter this with pending exception set
PRESERVE_EXCEPTION_MARK; // exceptions are never thrown, needed for TRAPS argument
//
Handle h_lock(THREAD, java_lang_ref_Reference::pending_list_lock());
assert(ObjectSynchronizer::current_thread_holds_lock(
JavaThread::current(), h_lock),
"Lock should be held");
// Notify waiters on pending lists lock if there is any reference.
if (java_lang_ref_Reference::pending_list() != NULL) {
ObjectSynchronizer::notifyall(h_lock, THREAD);
}
ObjectSynchronizer::fast_exit(h_lock(), pending_list_basic_lock, THREAD);
if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION;
}
lock 석방 후, ReferenceHandler 스 레 드 가 정상 작 동 에 들 어가 면 pending 중 Reference 대상 이 각자 의 것 을 눌 렀 습 니 다. Reference Queue 중
private static class ReferenceHandler extends Thread {
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
for (;;) {
Reference r;
synchronized (lock) {
if (pending != null) {
r = pending;
Reference rn = r.next;
pending = (rn == r) ? null : rn;
r.next = r;
} else {
try {
lock.wait();
} catch (InterruptedException x) { }
continue;
}
}
// Fast path for cleaners
if (r instanceof Cleaner) {
((Cleaner)r).clean();
continue;
}
ReferenceQueue q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
}
}
}
위 부분 에 서 는 JVM 이 GC 에 있 을 때 Weak HashMap 의 key 메모 리 를 풀 어 주 었 다 고 했 습 니 다. 그러면... Weak HashMap 에서 Entry 데 이 터 를 어떻게 방출 하 는 지 보 세 요. Weak Hash Map 의 Reference Queue 는 어떻게 작용 합 니까?
Entry 는 어떻게 정리 합 니까?
GC 이후 Weak HashMap 대상 에서 get, put 데이터 또는 size 방법 을 호출 할 때 Weak HashMap 은 HashMap 보다 하나 더 많 습 니 다. expungeStaleEntries () 방법
private void expungeStaleEntries() {
Entry<K,V> e;
while ( (e = (Entry<K,V>) queue.poll()) != null) {
int h = e.hash;
int i = indexFor(h, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;
if (p == e) {
if (prev == e)
table[i] = next;
else
prev.next = next;
e.next = null; // Help GC
e.value = null; // " "
size--;
break;
}
prev = p;
p = next;
}
}
}
expunge StaleEntries 방법 Reference Queue 열 에 있 는 WeakReference 를 poll 에 따라 나 와 Entry [] 데이터 와 비교 하 는 것 입 니 다. 같은 것 을 발견 하면 이 Entry 가 저장 한 대상 이 GC 에 의 해 제거 되 었 음 을 설명 합 니 다. 그러면 Entry [] 내의 Entry 대상 을 제거 하고 GC 에 의 해 떨 어 진 것 을 제거 합 니 다. Weak Reference 에 대응 하 는 Entry 는 Weak HashMap 에서 제거 되 었 습 니 다.
마지막.
public static void main(String[] args) {
Map<String, String> data = new WeakHashMap<String, String>();
data.put("123", "123");
data.put("124", "124");
data.put("125", "125");
data.put("126", "126");
System.gc();
data.size();
System.out.println(data);
}
코드 에서 System. gc () 를 호출 한 후 data 의 데이터 가 비 워 졌 습 니까?정 답 은 없어 요.
테스트 를 통 해 gc 가 모든 weakreference 대상 을 완전히 회수 할 수 있 는 것 은 아 닙 니 다. weakreference 도 old 구역 에 나타 날 수 있 습 니 다. 왜 GC 의 전략 을 봐 야 합 니까?
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.