๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๋นˆ ๊ตฌ๋ฉ ์ฑ„์šฐ๊ธฐ

[Java] ์ฐธ์กฐ ํƒ€์ž…(Reference Type) : Strong Reference, Soft Reference, Weak Reference, Phantom Reference

์ถœ์ฒ˜

ChatGPT


์ž๋ฐ”์—์„œ๋Š” ๋‹ค์–‘ํ•œ ์ฐธ์กฐ ํƒ€์ž…์„ ์ œ๊ณตํ•ด, ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์™€ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜(GC)์„ ๋” ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ๊ฐ๊ฐ์˜ ์ฐธ์กฐ ํƒ€์ž…์€ ๊ฐ์ฒด์˜ ์ƒ๋ช… ์ฃผ๊ธฐ์™€ ๋ฉ”๋ชจ๋ฆฌ ์ˆ˜์ง‘ ์ „๋žต์„ ๋‹ค๋ฅด๊ฒŒ ๊ด€๋ฆฌํ•˜๋„๋ก ๋•๋Š”๋‹ค. ์ž๋ฐ”๋Š” ๊ฐ•ํ•œ ์ฐธ์กฐ(Strong Reference)์™ธ์—๋„ ์•ฝํ•œ ์ฐธ์กฐ(Weak Reference), ๋ถ€๋“œ๋Ÿฌ์šด ์ฐธ์กฐ(Soft Reference) ๊ทธ๋ฆฌ๊ณ  ์œ ๋ น ์ฐธ์กฐ(Phantom Reference)๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ์ฐธ์กฐ ํƒ€์ž…๋“ค์€ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์˜ ํŠน์„ฑ๊ณผ ๊ฐ์ฒด์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

 

1. ์ฐธ์กฐ ํƒ€์ž…(Reference Types) ์„ค๋ช…

1.1 ๊ฐ•ํ•œ ์ฐธ์กฐ Strong Reference

๊ฐ•ํ•œ ์ฐธ์กฐ๋Š” ์ž๋ฐ”์˜ ๊ธฐ๋ณธ ์ฐธ์กฐ ํƒ€์ž…์œผ๋กœ, ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์ด๋‹ค.

๊ธฐ๋Šฅ

๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์กด์žฌํ•˜๋Š” ํ•œ, ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ๋Š” ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์ˆ˜์ง‘ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰, ํ”„๋กœ๊ทธ๋žจ์˜ ์‹คํ–‰ ๊ฒฝ๋กœ์—์„œ ๊ฐ์ฒด์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๋Š” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ œ๊ฑฐ๋˜์ง€ ์•Š๋Š”๋‹ค.

์˜ˆ์‹œ

Object obj = new Object();  // 'obj'๋Š” ๊ฐ•ํ•œ ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

 

์‚ฌ์šฉ ์ƒํ™ฉ

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ, ๊ฐœ๋ฐœ์ž๋Š” ๊ฐ์ฒด๋ฅผ ๊ฐ•ํ•œ ์ฐธ์กฐ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๊ฐ•ํ•œ ์ฐธ์กฐ๋Š” ๊ฐ์ฒด๊ฐ€ ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ๊ฐ€์ง€ ๊ฐ์ฒด๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์œ ์ง€ํ•œ๋‹ค.

1.2 ๋ถ€๋“œ๋Ÿฌ์šด ์ฐธ์กฐ(Soft Reference)

๋ถ€๋“œ๋Ÿฌ์šด ์ฐธ์กฐ๋Š” ๊ฐ์ฒด์— ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์—†๊ณ , ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ•  ๋•Œ๋งŒ GC์— ์˜ํ•ด ์ˆ˜์ง‘๋˜๋Š” ์ฐธ์กฐ ํƒ€์ž…์ด๋‹ค.

๊ธฐ๋Šฅ

JVM์€ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ•  ๋•Œ๋งŒ ๋ถ€๋“œ๋Ÿฌ์šด ์ฐธ์กฐ๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ์ˆ˜์ง‘ํ•œ๋‹ค. ์ด ํƒ€์ž…์˜ ์ฐธ์กฐ๋Š” GC๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ ์ƒํƒœ์—์„œ๋งŒ ์ˆ˜์ง‘ํ•˜๋ฏ€๋กœ, ๊ฐ์ฒด๋ฅผ ๊ฐ€๋Šฅํ•œ ํ•œ ์˜ค๋ž˜ ์œ ์ง€ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉํ•˜๋‹ค.

์˜ˆ์‹œ

import java.lang.ref.SoftReference;

SoftReference<Object> softRef = new SoftReference<>(new Object());
// softRef๋Š” ๋ถ€๋“œ๋Ÿฌ์šด ์ฐธ์กฐ์ž…๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ•  ๋•Œ๋งŒ ์ˆ˜์ง‘๋ฉ๋‹ˆ๋‹ค.

 

์‚ฌ์šฉ ์ƒํ™ฉ

์บ์‹œ์™€ ๊ฐ™์€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์—์„œ ์œ ์šฉํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์บ์‹œ์— ์ €์žฅํ•˜๊ณ , ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ•ด์งˆ ๋•Œ GC๊ฐ€ ์บ์‹œ๋ฅผ ์ •๋ฆฌํ•˜๋„๋ก ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉ๋œ๋‹ค.

 

1.3 ์•ฝํ•œ ์ฐธ์กฐ Weak Reference

์•ฝํ•œ ์ฐธ์กฐ๋Š” ๊ฐ์ฒด์•  ๋Œ€ํ•œ ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์—†์œผ๋ฉด, ์ฆ‰์‹œ GC์— ์˜ํ•ด ์ˆ˜์ง‘๋  ์ˆ˜ ์žˆ๋Š” ์ฐธ์กฐ ํƒ€์ž…์ด๋‹ค.

๊ธฐ๋Šฅ

์•ฝํ•œ ์ฐธ์กฐ๋กœ ์ฐธ์กฐ๋œ ๊ฐ์ฒด๋Š” ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ GC์˜ ๋‹ค์Œ ์‚ฌ์ดํด์—์„œ ์ˆ˜์ง‘๋œ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐ์ฒด๊ฐ€ ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์„๋•Œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ์‹œ

import java.lang.ref.WeakReference;

WeakReference<Object> weakRef = new WeakReference<>(new Object());
// weakRef๋Š” ์•ฝํ•œ ์ฐธ์กฐ์ž…๋‹ˆ๋‹ค. ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์—†์œผ๋ฉด ์ฆ‰์‹œ ์ˆ˜์ง‘๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์‚ฌ์šฉ ์ƒํ™ฉ

WekaHashMap๊ณผ ๊ฐ™์€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์—์„œ ํ‚ค๊ฐ€ ์•ฝํ•œ ์ฐธ์กฐ๋กœ ์œ ์ง€๋˜์–ด, ํ•ด๋‹น ํ‚ค์— ๋Œ€ํ•œ ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์—†์œผ๋ฉด ์ž๋™์œผ๋กœ ์—”ํŠธ๋ฆฌ๊ฐ€ ์ œ๊ฑฐ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์บ์‹œ๋‚˜ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ์—์„œ ํ‚ค์˜ ์ˆ˜๋ช…์ด ์งง๊ฑฐ๋‚˜ ์ž„์‹œ์ ์ด ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค.

 

1.4 ์œ ๋ น ์ฐธ์กฐ Phantom Reference

์œ ๋ น ์ฐธ์กฐ๋Š” ๊ฐ์ฒด๊ฐ€ GC์— ์˜ํ•ด ์ˆ˜์ง‘๋œ ํ›„์—๋„ ์กด์žฌํ•˜๋Š” ํŠน์ˆ˜ํ•œ ์ฐธ์กฐ ํƒ€์ž…์ด๋‹ค. ๊ฐ์ฒด์˜ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ํ•ด์ œ๋˜๊ธฐ ์ „์— ์ถ”๊ฐ€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

๊ธฐ๋Šฅ

์œ ๋ น ์ฐธ์กฐ๋Š” ๊ฐ์ฒด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์™„์ „ํžˆ ํ•ด์ œ๋˜๊ธฐ ์ „์— ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ •๋ฆฌ(clean-up) ์ž‘์—…์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค. ์œ ๋ น ์ฐธ์กฐ๋Š” ReferenceQueue์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋ฉฐ, ๊ฐ์ฒด์˜ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ๊ฐ€ ์ž„๋ฐ•ํ•œ ์‹œ์ ์—์„œ ์•Œ๋ฆผ์„ ๋ฐ›์„ ์ˆญ ใ…ฃใ…†๋‹ค.

์˜ˆ์‹œ

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(obj, refQueue);
// phantomRef๋Š” ์œ ๋ น ์ฐธ์กฐ์ž…๋‹ˆ๋‹ค. ๊ฐ์ฒด๊ฐ€ GC๋˜๊ธฐ ์ „์— ์•Œ๋ฆผ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
obj = null;  // ์ดํ›„ GC๊ฐ€ obj๋ฅผ ์ˆ˜๊ฑฐํ•ด๋„ phantomRef๋Š” ์ฐธ์กฐ ํ์— ๋“ค์–ด๊ฐ€๋ฉฐ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

 

์‚ฌ์šฉ ์ƒํ™ฉ

๋„ค์ดํŠธ๋ธŒ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ(์˜ˆ: ํŒŒ์ผ ํ•ธ๋“ค, ์†Œ์ผ“ ๋“ฑ)์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ, ๊ฐ์ฒด๊ฐ€ ์ˆ˜๊ฑฐ๋˜๊ธฐ ์ „์— ๋ฆฌ์†Œ์Šค๋ฅผ ํ•ด์ œํ•ด์•ผ ํ•  ๋Œ€ ์œ ์šฉํ•˜๋‹ค. ๋˜ํ•œ, ๋ณต์žกํ•œ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์™€ ๊ด€๋ จ๋œ ๊ณ ๊ธ‰ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ๋„ ์œ ๋ น ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋ฆฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

2. ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ์ฐธ์กฐ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ์ƒํ™ฉ

2.1 ์บ์‹œ ๊ตฌํ˜„์—์„œ์˜ ์‚ฌ์šฉ

๋ถ€๋“œ๋Ÿฌ์šด ์ฐธ์กฐ(Soft Reference)์™€ ์•ฝํ•œ ์ฐธ์กฐ(Weak Reference)๋Š” ์บ์‹œ ๊ตฌํ˜„์— ์œ ์šฉํ•˜๋‹ค. ์บ์‹œ๋Š” ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ– ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค. ํ•˜์ง€๋งŒ,๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ์œ„ํ•ด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ•  ๋Œ€ ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;

public class CacheExample {
    private Map<String, SoftReference<Object>> cache = new HashMap<>();

    public void addToCache(String key, Object value) {
        cache.put(key, new SoftReference<>(value));
    }

    public Object getFromCache(String key) {
        SoftReference<Object> ref = cache.get(key);
        if (ref != null) {
            return ref.get();  // ๋ถ€๋“œ๋Ÿฌ์šด ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜
        }
        return null;
    }
}

 

์œ„์˜ ์˜ˆ์ œ์—์„œ, SoftReference๋ฅผ ์‚ฌ์šฉํ– ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ ์‹œ ์ž๋™์œผ๋กœ GC์— ์˜ํ•ด ์ •๋ฆฌ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

 

2.2 ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ์—์„œ์˜ ์‚ฌ์šฉ

์œ ๋ น ์ฐธ์กฐ(Phantom Reference)๋Š” ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํŒŒ์ผ ํ•ธ๋“ค์ด๋‚˜ ๋„คํŠธ์›Œํฌ ์†Œ์ผ“๊ณผ ๊ฐ™์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด๋Š” GC์— ์˜ํ•ด ์ˆ˜์ง‘๋˜๊ธฐ ์ „์— ๋ฐ˜๋“œ์‹œ ๋ฆฌ์†Œ์Šค๋ฅผ ํ•ด์ œํ•ด์•ผ ํ•œ๋‹ค.

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class ResourceCleaner {
    private static class Resource {
        // ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด
    }

    private static class CleanupTask extends PhantomReference<Resource> {
        public CleanupTask(Resource referent, ReferenceQueue<? super Resource> q) {
            super(referent, q);
        }

        public void cleanup() {
            System.out.println("Cleaning up resources...");
            // ๋ฆฌ์†Œ์Šค ํ•ด์ œ ์ž‘์—… ์ˆ˜ํ–‰
        }
    }

    public static void main(String[] args) {
        ReferenceQueue<Resource> refQueue = new ReferenceQueue<>();
        Resource resource = new Resource();
        CleanupTask cleanupTask = new CleanupTask(resource, refQueue);

        resource = null;  // ๊ฐ•ํ•œ ์ฐธ์กฐ ํ•ด์ œ

        System.gc();  // GC ๊ฐ•์ œ ์‹คํ–‰

        // ์ฐธ์กฐ ํ์—์„œ ์œ ๋ น ์ฐธ์กฐ๋ฅผ ํ™•์ธํ•˜๊ณ , ์ •๋ฆฌ ์ž‘์—… ์ˆ˜ํ–‰
        CleanupTask polledTask = (CleanupTask) refQueue.poll();
        if (polledTask != null) {
            polledTask.cleanup();
        }
    }
}

 

์œ„์˜ ์˜ˆ์ œ์—์„œ PhantomReference๋Š” ReferenceQueue์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜์–ด, ๊ฐ์ฒด๊ฐ€ GC์— ์˜ํ•ด ์ˆ˜์ง‘๋˜๊ธฐ ์ง์ „์— ์ •๋ฆฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

 

3. ๊ฒฐ๋ก 

์ž๋ฐ”์˜ ๋‹ค์–‘ํ•œ ์ฐธ์กฐ ํƒ€์ž…์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๋ฐ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์„ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š”๋‹ค. ๊ฐ ์ฐธ์กฐ ํƒ€์ž…์€ ๊ฐ์ฒด์˜ ์ˆ˜๋ช… ๊ด€๋ฆฌ์— ์ž‡์–ด ๊ณ ์œ ํ•œ ์šฉ๋„์™€ ์ด์ ์„ ์ œ๊ณตํ•˜๋ฉฐ, ๊ฐœ๋ฐœ์ž๋Š” ํ”„๋กœ๊ทธ๋žจ์˜ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋งž๊ฒŒ ์ ์ ˆํ•œ ์ฐธ์กฐ ํƒ€์ž…์„ ์„ ํƒํ•ด ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ๊ณผ ์•ˆ์ •์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. SoftReference, WeakReference, ๊ทธ๋ฆฌ๊ณ  PhantomReference๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€ ์บ์‹œ ๊ด€๋ฆฌ, ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ ๋“ฑ ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.