일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 신입사원
- 개발
- CS
- IT
- 컴퓨터공학
- Effective Java
- 이펙티브 자바
- 알고리즘
- 컴퓨터과학
- 자바
- 신입
- 뮤텍스
- 깃허브
- 공채
- 운영체제
- 스프링
- 스터디
- 프로그래밍
- 우리카드
- 디지털
- OS
- java
- package-private
- github
- 세마포어
- Public
- spring
- 정보처리기사
- 메모리
- 깃
Archives
- Today
- Total
주니어 개발자 성장기
아이템 8. finalizer와 cleaner 사용을 피하라 본문
개요
자원 회수를 위해서 사용할 수 있는 finalizer
와cleaner
는 즉시 수행된다는 보장이 없으며 상황에 따라 위험할 수도 있어 불필요하다.
Finalizer
다음과 같이 클래스에 Object.finalize
메서드를 오버라이딩 해주면 된다.
@Override
protected void finalize() throws Throwable {
System.out.print("");
}
자바 9부터 Deprecated 되었다. 대안으로 AutoCloseable
, Cleaner
, WeakReference
, PhantomReference
등을 제시하고 있다. (AutoCloseable
가 제일 낫다고 한다)
또한 상속을 악용한 Finalizer
공격이 일어날 수도 있다.
Cleaner
다음과 같이 static class로 구현하면 된다.
// 해당 객체(this)를 내부에서 절대로 참조해선 안된다.
public static class ResourceCleaner implements Runnable {
private List<Object> resourceToClean;
public ResourceCleaner(List<Object> resourceToClean) {
this.resourceToClean = resourceToClean;
}
@Override
public void run() {
resourceToClean = null;
System.out.println("cleaned up.");
}
}
이렇게 구현한 클래스를 다음과 같이 사용하면 된다.
Cleaner cleaner = Cleaner.create();
// Cleaner의 대상이 될
List<Object> resourceToCleanUp = new ArrayList<>();
BigObject bigObject = new BigObject(resourceToCleanUp);
// Cleaner에 등록, 위에서 Runnable을 구현한 static 클래스를 2번째 매개변수로 넣어준다.
cleaner.register(bigObject, new BigObject.ResourceCleaner(resourceToCleanUp));
//bigObject의 참조가 해제되면 GC가 일어날 때 등록된 자원의 메모리가 해제된다.
권장 방법
AutoCloseable
과 try-with-resources
를 사용하는 것이다. Cleaner
는 안전망으로서 활용할 수도 있다. (클라이언트 코드에서 실수로 try-with-resources
를 사용하지 않을 경우 GC가 수행될 기회를 줄 수 있기 때문)
AutoCloseable
AutoCloseable
인터페이스를 활용하기 위해서 AutoCloseable.close
메서드를 재정의해야 한다.close
메서드는 기본 스펙에 다음과 같이 throws Exception이 정의되어 있다.
void close() throws Exception
하지만 오버라이딩 할 때 반드시 throws Exception을 해야하는 것이 아니다.
- 만약, 예외를 던져야 하는 상황이라면 throws Exception 대신에 throws {구체적인 예외 클래스}로 구현할 것을 권장한다. → 클라이언트 코드에 예외 처리 책임 전가
- 예외를 내부에서 처리할 수도 있다(try-catch 구문으로).
- 예외처리시 별다른 할 일이 필요하지 않을 때는 catch 구문에 단순히 throw new RuntimeException(e)를 추가해주는 것도 좋다.
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
- 가급적이면
close
메서드는 멱등성을 가지도록 권장한다. (클라이언트가 같은 인스턴스의close
를 여러번 호출할 가능성이 있기 때문)
Finalize 공격에 대비
- 클래스를 final로 선언한다.
finalize
를 미리 final로 선언해서 오버라이딩을 막는다.- 호출을 방어하고자 하는 메서드에 검증 절차를 추가한다.
@Override
final protected void finalize() throws Throwable {
super.finalize();
}
public void transfer(BigDecimal amount, String to) {
if(this.accountId.equals("푸틴"))
throw new IllegalArgumentException("푸틴은 계정을 막습니다.");
System.out.printf("transfer %f from %s to %s\n", amount, accountId, to);
}
'Java > 이펙티브 자바' 카테고리의 다른 글
아이템 10. equals는 일반 규약을 지켜 재정의하라 (0) | 2023.07.28 |
---|---|
아이템 9. try-finally 보다 try-with-resources를 사용하라. (0) | 2023.07.23 |
아이템 7. 다 쓴 객체 참조를 해제하라. (0) | 2023.07.20 |
아이템 6. 불필요한 객체 생성을 피하라 (0) | 2023.07.17 |
아이템 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라. (0) | 2023.07.15 |