자바에는 finalizer, cleaner 두 개의 객체 소멸자를 제공한다. finalizer는 모든 클래스가 override(재정의) 할 수 있다.
@Override
protected void finalize() throws Throwable {
super.finalize();
}
finalizer은 자바 9에서는 사용 자제 API로 지정했다. 사용 자제로 설정한 이유는 크게 3가지 있다.
1.finalize는 가비지 컬렉션이 객체 메모리를 정리 한 후에 실행이 될 수도 있고 안 될 수도 있다. 이 말은 실행 시점뿐 아니라 실행 여부조차 보장하지 않는다.
2.속도 측면에서 느려진다.
3.finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수도 있다.
finalizer 공격이란? finalizer 메서드를 사용하는 객체를 상속해서 finalizer를 재정의 하여 애초에는 허용되지 않았을 작업을 수행하는 것이다.
public class Order {
public Order(String mbrNm) throws IllegalAccessException {
if(mbrNm.equals("홍길동")) {
throw new IllegalAccessException();
}
}
public void orderStart(String mbrNm) {
System.out.println(mbrNm + "주문을 시작하겠습니다");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
}
}
위의 코드는 홍길동이라는 이름을 가진 사람은 Order 객체를 생성 시 예외를 발생시키는 코드이다. 평소에는 문제가 없는 코드이지만 Order 클래스를 상속하는 클래스가 생기면 문제가 발생한다.
public class AttackOrder extends Order {
public AttackOrder(String mbrNm) throws IllegalAccessException {
super(mbrNm);
}
@Override
protected void finalize() throws Throwable {
super.orderStart("홍길동");
}
}
Order 클래스를 상속하는 AttackOrder이고 finalize를 재정의 하고 있다.
public static void main(String[] args) throws InterruptedException {
Order order = null;
try{
order = new AttackOrder("홍길동");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.gc();
Thread.sleep(3000L);
}
홍길동이라는 이름이 들어가기 때문에 exception이 발생하지만 가비지 컬렉터가 order 메모리를 정리를 하고 재정의한 finalize 메서드가 실행되면서 기존에 실행할 수 없는 orderStart가 실행이 된다. cleaner는 finalize보다는 안전하지만 그래도 사용하지 말자.
cleaner or finalize를 사용하고 싶으면 try-with-resources를 사용하자. try 안에 AutoCloseable을 구현하고 있는 객체를 넘길 시 gc 이후에 close메서드를 실행한다.
'이펙티브 자바' 카테고리의 다른 글
equals는 일반 규약을 지켜 재정의하라 (0) | 2022.09.06 |
---|---|
try-finally 보다는 try-with-resources를 사용하라 (0) | 2022.09.03 |
다 쓴 객체 참조를 해제하라 (0) | 2022.08.28 |
불필요한 객체 생성을 피하라 (0) | 2022.08.24 |
자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.08.23 |