2023. 1. 21. 20:54ใJAVA/Effective JAVA
item07. ๋ค ์ด ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ํด์ ํ๋ผ.
" p38. WeakHashMap, ์ฝํ ์ฐธ์กฐ (Weak reference)"
WeakHashMap์ด๋?
: ๋์ด์ ์ฌ์ฉํ์ง ์๋ ๊ฐ์ฒด๋ฅผ GCํ ๋ ์๋์ผ๋ก ์ญ์ ํด์ฃผ๋ Map์ด๋ค.
์ด๋ ๋งต์ value๊ฐ ์๋๋ผ key๋ฅผ ๊ธฐ์ค์ผ๋ก key๋ฅผ ๋์ด์ ๊ฐํ๊ฒ ์ฐธ์กฐ๋๋ ๊ณณ์ด ์๋ค๋ฉด ํด๋น ์ํธ๋ฆฌ๋ฅผ ์ ๊ฑฐํ๋ค.
๊ทธ๋ฌ๋ฏ๋ก ๋งต์ key์ ์์กดํ๋ ๊ฒฝ์ฐ์ ์ฌ์ฉํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๋ ์กฐ์ฌํด์ผ ํ๋ ๊ฒ์ Integer, String ๊ณผ ๊ฐ์ ๊ฐ๋ค์ ๋์ด์ ์ฌ์ฉํ์ง ์๋๋ค๊ณ ํ๋๋ผ๋ ์ ๊ฑฐ๋์ง ์๋๋ค..!!
์ด๋๊ฐ์ ๊ฐ์ด ์ ์ฅ? ๋์ด ์๊ธฐ ๋๋ฌธ์ด๋ค.
package chapter01.item07.cache;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import org.springframework.cglib.core.WeakCacheKey;
/**
* item07. ๋ค ์ด ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ํด์ ํ๋ผ.
*/
public class PostRepository
{
private Map<CacheKey, Post> cache;
public PostRepository()
{
this.cache = new WeakHashMap<>();
}
public Post getPostById(Integer id)
{
CacheKey key = new CacheKey(id);
if (cache.containsKey(key)) {
return cache.get(key);
}else {
Post post = new Post(); // TODO DB์์ ์ฝ์ด์ค๊ฑฐ๋ REST API๋ฅผ ํตํด ์ฝ์ด์ฌ ์ ์๋ค.
cache.put(key, post);
return post;
}
}
public Map<CacheKey, Post> getCache()
{
return cache;
}
}
@Test
void cache() throws InterruptedException
{
PostRepository postRepository = new PostRepository();
Integer p1 = 1;
postRepository.getPostById(p1);
assertFalse(postRepository.getCache().isEmpty());
System.out.println("run gc");
System.gc();
System.out.println("wait");
Thread.sleep(3000L);
assertTrue(postRepository.getCache().isEmpty());
}
ํด๋น ํ ์คํธ๋ฅผ ์คํํด๋ณด๋ฉด key๋ฅผ ๊ฐํ๊ฒ ์ฐธ์กฐํ๋ ๊ณณ์ด ์๊ธฐ ๋๋ฌธ์ GCํ ๋ ์บ์๊ฐ ์ง์์ง๋ฉด์ ํ ์คํธ ์ฑ๊ณตํ๋ ๊ฒ์ ์ ์ ์๋ค.
๐ก WeakHashMap๋ ์บ์๋ฅผ ๊ตฌํํ๋๋ฐ ์ฌ์ฉํ ์ ์์ง๋ง, ์บ์๋ฅผ ์ง์ ๊ตฌํํ๋ ๊ฒ์ ๊ถ์ฅํ์ง ์๋๋ค!!
๋ ํผ๋ฐ์ค ์ข ๋ฅ
- strong reference
: ๊ทธ๋ฅ ํํ๊ฒ = ๋ฅผ ์ฌ์ฉํด์ ํ๋ ๋ฐฉ๋ฒ์ strong reference๋ผ๊ณ ํ๋ค.
ArrayList<Channel> channelList = new ArrayList<>(); -> ์ด๋ฐ ๋ฐฉ๋ฒ
- soft reference
public class SoftReferenceExample {
public static void main(String[] args) throws InterruptedException {
Object strong = new Object();
SoftReference<Object> soft = new SoftReference<>(strong);
strong = null;
System.gc();
Thread.sleep(3000L);
// softReference๋ GC์ ๋์์ด ๋๊ธฐ๋ ํ์ง๋ง..
// ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ถ์กฑํ ๋ ์ ๊ฑฐํ๊ธฐ ๋๋ฌธ์ ์ง๊ธ์ ์ฌ๋ผ์ง์ง ์์ ๊ฒ์ด๋ค. (๋ฉ๋ชจ๋ฆฌ๊ฐ ์ง๊ธ์ ์ถฉ๋ถํ๊ธฐ ๋๋ฌธ)
System.out.println(soft.get());
}
}
SoftReference๋ GC์ ๋์์ด ๋๊ธฐ๋ ํ์ง๋ง ๋ฐ๋ก ์ ๊ฑฐ๋๋๊ฒ ์๋๋ผ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ถ์กฑํด์ง ์ํฉ์ด๋ฉด ๊ทธ๋ ์ ๊ฑฐํ๋ค.
- weak reference
public class WeakReferenceExample {
public static void main(String[] args) throws InterruptedException {
Object strong = new Object();
WeakReference<Object> weak = new WeakReference<>(strong);
strong = null;
System.gc();
Thread.sleep(3000L);
// WeakReference๋ ์ ๊ฑฐ๋๋ค. (soft๋ณด๋ค ์ฝํ๊ฒ ์ฐธ์กฐํ๋ ์ํ์ด๊ธฐ ๋๋ฌธ์)
System.out.println("weak.get() = " + weak.get());
}
}
weak referecnce๋ soft๋ณด๋ค ์ฝํ ์ฐธ์กฐ๋ก weak referecne๋ ์ฐธ์กฐ๋๋ ๋ถ๋ถ์ด ์๋ค๋ฉด GC ํ ๋ ์ ๊ฑฐํ๋ค.
- phantom reference
public class PhantomReferenceExample {
public static void main(String[] args) throws InterruptedException {
BigObject strong = new BigObject();
ReferenceQueue<BigObject> rq = new ReferenceQueue<>();
PhantomReference<BigObject> phantom = new PhantomReference<>(strong,rq);
strong = null;
System.gc();
Thread.sleep(3000L);
// ์ฌ๋ผ์ง์ง๋ ์๊ณ queue์ ๋ค์ด๊ฐ๋ค.
System.out.println("phantom.isEnqueued() = " + phantom.isEnqueued());
Reference<? extends BigObject> reference = rq.poll();
reference.clear(); // ์ด๋ ๊ฒ ํ๋ฉด ์ต์ข
์ ์ผ๋ก ์ฌ๋ผ์ง๋ค.
}
}
phantom reference๋ ์ข ๋ ์ด๋ ค์ด๋ฐ GCํ ๋ ์ฌ๋ผ์ง๋ ๊ฒ์ด ์๋๋ผ ReferenceQueue์ ๋ค์ด๊ฐ๋ค.
๋ค์ด๊ฐ ๊ฒ์ ํ์ธํ ์ ์๊ณ , reference์ ๋ํด์ clear๋ฅผ ํ๋ฉด queue์ ๋ค์ด๊ฐ๋ ๊ฐ๋ ์ ๊ฑฐํ๊ฒ ๋๊ณ , ์ด๋ฌ๋ฉด ์ต์ข ์ ์ผ๋ก ์ ๊ฑฐ๋๋ค.
Phantom reference๋ก ์์ ํด์ ํ ๋ ์ฌ์ฉํ ์๋ ์๋๋ฐ ๊ทธ๋ด ๋๋ ์ง์ ์ปค์คํ ํด์ ์ฌ์ฉํด์ผ ํ๋ค.
package chapter01.item07.reference;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
/**
* ์์์ ๋ฐ๋ฉํ๊ณ ์ถ์ ์ฉ๋๋ก ์ฌ์ฉํ ๋
*/
public class BigObjectReference<BigObject> extends PhantomReference<BigObject> {
/**
* Creates a new phantom reference that refers to the given object and
* is registered with the given queue.
*
* <p> It is possible to create a phantom reference with a {@code null}
* queue, but such a reference is completely useless: Its {@code get}
* method will always return {@code null} and, since it does not have a queue,
* it will never be enqueued.
*
* @param referent the object the new phantom reference will refer to
* @param q the queue with which the reference is to be registered,
* or {@code null} if registration is not required
*/
public BigObjectReference(BigObject referent, ReferenceQueue<? super BigObject> q) {
super(referent, q);
}
// ์์๋ก ๋ง๋ ๊ฒ (์ฌ๊ธฐ์ ์์ ๋ฐ๋ฉ์ ํ๊ฒ ๋ค~)
public void cleanUp() {
System.out.println("clean up!!");
}
}
public class PhantomReferenceExample {
public static void main(String[] args) throws InterruptedException {
BigObject strong = new BigObject();
ReferenceQueue<BigObject> rq = new ReferenceQueue<>();
PhantomReference<BigObject> phantom = new PhantomReference<>(strong,rq);
strong = null;
System.gc();
Thread.sleep(3000L);
// ์ฌ๋ผ์ง์ง๋ ์๊ณ queue์ ๋ค์ด๊ฐ๋ค.
System.out.println("phantom.isEnqueued() = " + phantom.isEnqueued());
Reference<? extends BigObject> reference = rq.poll();
BigObjectReference bigObjectCleaner = (BigObjectReference) reference;
bigObjectCleaner.cleanUp(); // ์์ ๋ฐ๋ฉ ๋ฉ์๋ ์คํ
reference.clear(); // ์ด๋ ๊ฒ ํ๋ฉด ์ต์ข
์ ์ผ๋ก ์ฌ๋ผ์ง๋ค.
}
}
์ด๋ ๊ฒ ํด์ ์์ ๋ฐ๋ฉ์ ํ ์๋ ์๋ค.
๐ฅ ๊ทผ๋ฐ ์ง๊ธ๊น์ง SoftReference ๋ WeakReference, PhantomReference๋ ๋ณธ ์ ์ด ์๋๋ฐ
์์ฒญ ํฐ Object๊ฐ ์๋ค๊ฑฐ๋ ์ด๋ฌ์ง ์๋๋ค๋ฉด ์ฌ์ค ๊ฑฐ์ ์ฌ์ฉ๋ ์ผ์ด ์๋ค๊ณ ํ๋ค.
SoftReference๋ Weak ์ด๋ฐ๊ฑด ์ธ์ ์์ ํด์ ๋๋์ง๋ ์๊ธฐ ์ด๋ ต๊ณ ์ ๋งคํ๊ธฐ ๋๋ฌธ์ ๋๋ ๊ทธ๋ฅ ๋ช ์์ ์ผ๋ก ์์ ํด์ ํด์ฃผ๋ ๊ฒ์ด ๋ ์ข๋ค๊ณ ์๊ฐํ๋ค.