2-2 ๋ค ์ด ๊ฐ์ฒด์ฐธ์กฐ๋ฅผ ํด์ ํ๋ผ.
by JiwonDev๋ฉ๋ชจ๋ฆฌ ๋์๋ ๊ฒ์ผ๋ก ์ ๋๋ฌ๋์ง ์๋๋ค.
์ค๋๋ ์์คํ ์์๋ ์ฝ๋๋ฆฌ๋ทฐ, ํํ๋กํ์ผ๋ฌ ๋ฆฌ๋ทฐ๋ฅผ ํ๋ค๋ณด๋ฉด ํ์์๋ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์๋ ๊ฐ ์ ๋ณตํ๋ ๊ฒฝ์ฐ๋ ํํ๋ค.
# ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ง์ ๊ด๋ฆฌํ๋ ํด๋์ค๋ผ๋ฉด ๋์์ ์ฃผ์ํ๋ผ. (Stack, Array ๋ฑ)
์๋ ์ฝ๋์์ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ์ฌํ๊ฒ ๋ฐ์ํ๊ณ ์๋ค. ์ด๋์ธ์ง ์ฝ๊ฒ ์ฐพ์ ์ ์๋๊ฐ?
// "๋ฉ๋ชจ๋ฆฌ ๋์(memory leak)"๊ฐ ์ด๋์ ์๊ธฐ๋์ง ๋ณด์ด๋๊ฐ?
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
if (elements.length == size) // ๊ณต๊ฐ์ด ๋ถ์กฑํ๋ค๋ฉด ์คํ ํฌ๊ธฐ๋ฅผ 2๋ฐฐ์ฉ ๋๋ฆฐ๋ค.
elements = Arrays.copyOf(elements, 2 * size + 1);
}
๋ฐ๋ก element[--size] ์ด๋ค. ๋์ด์ ์ฌ์ฉํ์ง ์๋ ๋ฉ๋ชจ๋ฆฌ์ธ๋ฐ๋ ์ฐธ์กฐ๋ ๊ทธ๋๋ก ์ ์ง๋๊ณ ์๋ค.
์๋ฐ์ ๊ฐ๋น์ง์ปฌ๋ ํฐ(GC)๋ ์ฐธ์กฐ์ฌ๋ถ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ ํด์ ํ๋ค. ์ฌ์ฉํ์ง๋ ์๋ ๊ณณ์์ ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด๋ค. ์์ ์์ ๋ ๊ทธ๋๋ง ๋์๋ฅผ ์ฐพ๊ธฐ ์ฌ์ดํธ์ด๋ค. ์บ์ (key-value)๋ ๋ฆฌ์ค๋์ ์ฝ๋ฐฑ(callback)์ ์ฌ์ฉํ ๋ ์์ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ฃผ ๋ฐ์ํ๋ค๊ณ ์๊ฐํ๋ฉด ๋์ฐํ๋ค.
map.put(key1, "test a");
map.put(key2, "test b");
key1 = null;
/* ... ๋ค๋ฅธ ์ฝ๋ ... */
// ์๋น์ค์์๋ ์ฌ์ฉ๋์ง ์์ง๋ง map์ ์๋ key1์ ๋ฐ์ดํฐ์ ์ฐธ์กฐ๋ ๊ณ์ ๋จ์์๋ค.
๋ํ JVM์ GC๊ฐ ์ด๋ฌํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฐพ์์ ํ ๋น ํด์ ํด์ค๋ค๊ณ ํ๋ค, ํฐ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์๋ค.
GC์์๋ ํฌ๊ฒ Young ์์ญ๊ณผ Old ์์ญ์ด ์กด์ฌํ๋๋ฐ, ์ด๋ฐ์์ผ๋ก ๊ณ์ํด์ ์ฐธ์กฐํ๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ๋ Old ์์ญ๊น์ง ์ฎ๊ฒจ์ง๊ฒ ๋๊ณ Old ์์ญ์ ์์ธ ๋ฉ๋ชจ๋ฆฌ๋ ํ๋ก๊ทธ๋จ ๊ตฌ๋์ ์ ๊น ๋ฉ์ถฐ๋ฒ๋ฆฌ๊ณ (Stop-the-World) ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ํด์ ํ๋ค.
(G1GC ์ด์ ์๋) ์๋ฒ์ปดํจํฐ์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์๋์ปค์, Old ์์ญ์ ์ด๋ฌํ ๋ฐ์ดํฐ๊ฐ ์์ด๊ฒ๋๋ค๋ฉด JVM์ GC๊ฐ Old ์์ญ์ ๋น์ฐ๊ธฐ ์ํด์ ์๋ฒ๊ฐ 2~3๋ถ๊ฐ ๋ฉ์ถฐ๋ฒ๋ฆด ์ ์๋ค. ์ฅ์ ๊ฐ ๋๊ฒ๋, ๋ก์ง์ ์ค๋ฅ๊ฐ ์๋ ๊ฒ๋ ์๋๋ฐ ๋ง์ด๋ค.
# ํด๊ฒฐ์ฑ
๊ฐ๋จํ๋ค. ๋ค์ด ๊ฐ์ฒด๋ ์ฐธ์กฐ๋ฅผ ํด์ ํด์ฃผ๋ฉด ๋๋ค.
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object results = elements[--size];
elements[size] = null; // ๋ง๊ธฐ ์ฐธ์กฐ ์ ๊ฑฐ
return results;
}
๋ค๋ง ์์ ๊ฐ์ด null์ ์ฌ์ฉํ๋ ๊ฑด NullPointException ๋๋ฌธ์ ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ๋ ์๊ฒจ๋ฒ๋ฆฐ๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์๋ฐ์๋ Weak ์๋ฃํ (WeakHashMap)๋ฑ์ ์ ๊ณตํด์ค๋ค. ๊ธฐ์กด์ ์๋ฃํ๊ณผ ์ฌ์ฉ๋ฒ์ ๋์ผํ๋ ๊ฐ์ ์ง์ ์ฐธ์กฐํ๋๊ฒ ์๋๋ผ ์ฐธ์กฐ ๊ฐ์ฒด(WeakReference)๋ฅผ ํตํด ๊ฐ์ง๊ณ ์๋ค๊ฐ ํด๋น ๊ฐ์ด ๋ ์ด์ ์ฌ์ฉ๋์ง ์๋๋ค๊ณ ํ๋จํ๋ฉด (prime == null์ด ๋๋ค๋ฉด) ํด๋น ์์๋ฅผ ์ ๊ฑฐํ๊ณ GCํด๋ฒ๋ฆฐ๋ค.
- Weak ์๋ฃํ์ ๊ธฐ์กด์ ์๋ฃํ๊ณผ ๋๊ฐ์ด ๋ฉํฐ์ค๋ ๋์ ์์ ํ์ง ์๋ค.
- Weak ์๋ฃํ์ ๊ฑฐ์น์ง ์๊ณ , Key๋ฅผ ์ง์ ์ฐธ์กฐํด๋ฒ๋ฆฌ๋ฉด ์๋ฌด๋ฐ ์๋ฏธ๊ฐ ์์ด์ง๋ค. WeakReference๋ก ์ฐธ์กฐํด์ผํ๋ค.
public class WeakHashMapTest {
public static void main(String[] args) {
WeakHashMap<Integer, String> map = new WeakHashMap<>();
Integer key1 = 1000;
Integer key2 = 2000;
map.put(key1, "test a");
map.put(key2, "test b");
key1 = null;
// map์์๋ ์ญ์ ๋ ๊ฒ์ด ์๋๋ค. ํด๋น ๋ฉ๋ชจ๋ฆฌ๊ฐ ๊ทธ๋๋ก ์ ์ง๋์ด์๋ค.
// ํ์ง๋ง WeakReference ์ prime = null์ด ๋์๋๋ค.
// ์ฆ GC๊ฐ ๋ฐ์ํ ๋ ํด๋น ์์์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ญ์ ๋๋ค.
}
}
# ๊ฐ์ฒด์ ๊ธฐ๋ณธ ์ข ๋ฃ์ (finalizer, Cleaner)๋ฅผ ์ฌ์ฉํ์ง ๋ง๋ผ
Java 9 ์ดํ ์์ด์ง ๋ฉ์๋๋ผ ๋ชจ๋ฅผ ์ ์์ง๋ง ์๋ฐ์ Object ๊ฐ์ฒด์๋ finalizer()๊ฐ ์กด์ฌํ์๋ค.
์ด๋ฅผ ํธ์ถํ๋ค๊ณ ํด์ ๋ฐ๋ก ์ญ์ ๋๋ ๊ฒ๋์๋๊ณ , Lock์ด ๊ฑธ๋ ค ํ๋ก๊ทธ๋จ ์ ์ฒด๊ฐ ๋ธ๋ญ๋ ์ ์๋ ์น๋ช ์ ์ธ ๋ฉ์๋์๋ค.
@Override
public void finalize() {
// ...
}
Java 9 ์ดํ์๋ Cleaner ๊ฐ ์๋ฉธ์๋ก ๋์ ๋์์ผ๋ฉฐ, ๋ณดํต AutoCloseable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ ๋ฑ๋ก๋ ์ค๋ ๋์ ์ ์๋ ํด๋ฆฐ ์์ ์ ์ํํ๋ค. ์ด๋ฅผ ํตํด try-with-resource ๋ฌธ์ ๋์์ ์ง์ ๊ตฌํํ ์ ์๋ค.
try(Worker worker = new Worker()) {
worker.work();
} catch(...) {
}
public class CleaningRequiredObject implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.createโ();
private static class CleanData implements Runnable {
@Override
public void run() {
// ์ฌ๊ธฐ์ ํด๋ฆฐ ์์
์ํ
}
}
private final CleanData;
private final Cleaner.Cleanable cleanable
public CleaningRequiredObject() {
this.cleanData = new CleanData();
// cleanable ๋ฑ๋ก
this.cleanable = cleaner.register(this, state);
}
@Override
public void close() {
cleanable.clean();
}
}
ํ์ง๋ง DB Connector๋ฅผ ์ง์ ๊ตฌํํ๋ ์์ค์ด ์๋๋ผ๋ฉด, ๋ณดํต์ ์ฌ์ฉํ ์ผ์ด ๊ฑฐ์ ์๋ค.
Java9์ Cleaner๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํ๋ค ์ฑ๋ฅ์ ๋ฌธ์ ๊ฐ ๋ง๊ณ , ๊ฐ์ฒด ์ง๋ ฌํ(Serialize)๋ฅผ ํตํ ๋ณด์์ ์ธ ๋ฌธ์ ์ ์ํ ์์ ์ ๋ณด์ฅํด์ฃผ์ง ์๋๋ค๋ ๊ฑด ์ฌ์ ํ ๋๊ฐ๋ค. ์ ๋ง ํ์ํ ๊ฒฝ์ฐ (๋ค์ดํฐ๋ธ ๋ฉ์๋ - JNI๋ฅผ ์ง์ ๊ตฌํ)๊ฐ ์๋๋ผ๋ฉด ์ฌ์ฉํ์ง ๋ง์์ผ ํ ๋ฉ์๋์ด๋ค.
'๐ฑBackend > Effective-Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
5-1 ์ ๋ค๋ฆญ์ ๊ทธ๋ฅ Raw ๋ก ์ฌ์ฉํ์ง ๋ง๋ผ(+ ๋น๊ฒ์ฌ ๊ฒฝ๊ณ ์ ๊ฑฐ) (0) | 2021.09.15 |
---|---|
4-1 ์์, ์ธํฐํ์ด์ค, ํด๋์ค์ ๊ถํ ์ต์ํ(+Java9 ๋ชจ๋) (0) | 2021.09.15 |
3-4 Cloneable์ ์ฌ์ฉํ์ง ๋ง๋ผ & Comparable์ ์ฌ์ฉ (0) | 2021.09.15 |
3-1 Equals์ toString์ ์ฌ์ ์ (0) | 2021.09.15 |
2-1 ์์ฑ์๋ฅผ ๋์ ํ๋ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋ (0) | 2021.09.15 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev