[์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ”] Item07 ์™„๋ฒฝ๊ณต๋žต. WeakHashMap

2023. 1. 21. 20:54ใ†JAVA/Effective JAVA

728x90
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 ์ด๋Ÿฐ๊ฑด ์–ธ์ œ ์ž์› ํ•ด์ œ ๋˜๋Š”์ง€๋„ ์•Œ๊ธฐ ์–ด๋ ต๊ณ  ์• ๋งคํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋„ ๊ทธ๋ƒฅ ๋ช…์‹œ์ ์œผ๋กœ ์ž์› ํ•ด์ œํ•ด์ฃผ๋Š” ๊ฒƒ์ด ๋” ์ข‹๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90