1_명시적 자원 해지
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364package
kr.co.ioacademy;
//iocademy 윤찬식 강사님
import
java.awt.Image;
import
java.io.IOException;
import
java.net.URL;
import
javax.imageio.ImageIO;
// 핵심 : 객체 내부에서 비 메모리 자원을 사용한다면 명시적 종료 메소드를 제공해야 한다.
// 이유
// 1. 가비지 컬렉션은 메모리만 수집한다.
// 2. 가비지 컬렉션이 수거하지 않는 비 메모리 자원에 대해서는
// 프로그래머가 관리 해야 한다.
// 3. finalize() - 종료자
// 개념 : 더 이상 참조할 수 없는 객체의 메모리 공간을 회수 할 때 GC에 의해서 호출되는 메소드
// 문제 : finalize()를 비 메모리 자원을 정리하는 용도로 사용하면 안된다.
// 1. 즉시 실행된다는 보장이 없다.
// 예) 종료자 안에서 파일 닫기. - JVM은 종료자를 천천히 실행하므로,
// 열린 상태의 파일이 많이 남아 있을 수 있다.
// 한번에 열 수 있는 파일의 개수에 제한이 있으므로 오류가 날 수 있다.
// - 종료자의 실행 시점은 JVM의 구현에 의존한다.
// 2. 반드시 실행된다는 보장도 없다.
// - 자바 명세에는 종료자가 즉시 실행되어야 한다는 문구도 없지만,
// 종료자가 반드시 실행되어야 한다는 문구도 없다.
// 즉 종료자가 실행되지 않은 객체가 남은 상태로 프로그램이 종료할 수도 있다.
// (동기화 객체 같은 것을 절대 종료자를 통해 반납하면 안된다)
class
WebPhoto {
Image image;
// 명시적인 종료 메소드 - OutputStream, InputStream, Socket 등
public
void
release() {
if
(image !=
null
) {
image.flush();
}
}
public
WebPhoto(String imageUrl) {
URL url;
try
{
url =
new
URL(imageUrl);
image = ImageIO.read(url);
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
public
class
Example1 {
public
static
void
main(String[] args)
throws
InterruptedException {
// WebPhoto가 더 이상 사용되지 않는다면, 객체 내부에서 사용하고 있는
// 자원에 대해서 정리가 필요하다.
WebPhoto photo =
new
WebPhoto(
"http://cfs7.tistory.com/image/14/tistory/2008/08/29/04/53/48b702410053a"
);
// photo = null;
// photo.release();
// System.gc();
}
}
2_finalize
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364package
kr.co.ioacademy;
//iocademy 윤찬식 강사님
import
java.awt.Image;
import
java.io.IOException;
import
java.net.URL;
import
javax.imageio.ImageIO;
// finalize()의 용도
// : 명시적 종료 메소드 호출을 잊은 경우의 안정망을 제공할 수 있다.
// 1. 그런 자원을 발견한 경우 반드시 경고 메세지를 남겨야 한다. (클라이언트 코드에 버그가 있는 것이므로)
// 2. 부모의 종료자를 명시적으로 호출해야 한다.
class
WebPhoto {
Image image;
/*
@Override
public void finalize() {
if (image != null) {
System.err.println("Explicit termination method 'release' is not called");
release();
}
}
*/
@Override
public
void
finalize()
throws
Throwable {
try
{
if
(image !=
null
) {
System.err.println(
"Explicit termination method 'release' is not called"
);
release();
}
}
finally
{
super
.finalize();
}
}
// 명시적인 종료 메소드 - OutputStream, InputStream, Socket 등
public
void
release() {
if
(image !=
null
) {
image.flush();
}
}
public
WebPhoto(String imageUrl) {
URL url;
try
{
url =
new
URL(imageUrl);
image = ImageIO.read(url);
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
public
class
Example2 {
public
static
void
main(String[] args)
throws
InterruptedException {
// System.gc();
}
}
3_finalize2
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485package
kr.co.ioacademy;
//iocademy 윤찬식 강사님
import
java.awt.Image;
import
java.io.IOException;
import
java.net.URL;
import
javax.imageio.ImageIO;
// 명시적 자원 해지가 필요한 클래스는 결국 중복된 코드를 작성해야 한다.
// 종료자의 역활을 일반화한 클래스
final
class
CloseGuard {
public
static
CloseGuard get() {
return
new
CloseGuard();
}
private
CloseGuard() {}
private
Throwable site;
public
void
open(String closer) {
if
(closer ==
null
)
throw
new
NullPointerException(
"closer == null"
);
String message =
"Explicit termination method '"
+ closer +
"' not called"
;
site =
new
Throwable(message);
}
public
void
close() {
site =
null
;
}
public
void
warnIfOpen() {
if
(site ==
null
)
return
;
System.err.println(site.toString());
}
}
class
WebPhoto {
private
Image image;
// Surface.java
private
final
CloseGuard mCloseGuard = CloseGuard.get();
@Override
public
void
finalize()
throws
Throwable {
try
{
if
(mCloseGuard !=
null
) mCloseGuard.warnIfOpen();
release();
}
finally
{
super
.finalize();
}
}
public
void
release() {
if
(image !=
null
) {
image.flush();
}
if
(mCloseGuard !=
null
) mCloseGuard.close();
}
public
WebPhoto(String imageUrl) {
URL url;
try
{
url =
new
URL(imageUrl);
image = ImageIO.read(url);
mCloseGuard.open(
"release"
);
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
public
class
Example3 {
public
static
void
main(String[] args) {
// System.gc();
}
}
4_finalize3
: Finalizer Guardian Idiom(종료자 보호 패턴)
: Image를 상속 받은 클래스(MyImage)의 객체 생성 -> 상위 클래스 Image 객체도 생성 -> MyImage 객체가 GC에 의해 해지 당할 때 하 상위 클래스(Image)의 guardian이란 멤버 변수도 해지 대상이 되고, 여기서 finalize() 호출123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051package
kr.co.ioacademy;
//iocademy 윤찬식 강사님
class
Image {
public
void
release() {
System.out.println(
"Image 자원 해지"
);
}
// @Override
// protected void finalize() throws Throwable {
// try {
// System.out.println("Image finalize!");
// release();
// } finally {
// super.finalize();
// }
// }
// 하위 클래스가 부모 클래스의 finalize()를 잊는 문제를
// 방지하는 방법. - (종료자 보호 패턴)Finalizer Guardian Idiom
@SuppressWarnings
(
"unused"
)
private
final
Object guardian =
new
Object() {
@Override
protected
void
finalize()
throws
Throwable {
release();
}
};
}
class
MyImage
extends
Image {
@Override
protected
void
finalize()
throws
Throwable {
System.out.println(
"MyImage finalize!"
);
// 잊었다.!!!
// super.finalize();
}
}
public
class
Example4 {
public
static
void
main(String[] args)
throws
InterruptedException {
MyImage image =
new
MyImage();
image =
null
;
System.gc();
Thread.sleep(
10000
);
}
}
'Programing > Java' 카테고리의 다른 글
Effective Java - 불변 객체 (0) | 2016.03.07 |
---|---|
Effective Java - 객체 비교, 복제 (0) | 2016.03.04 |
Junit 사용하기 (0) | 2016.03.03 |
Effective Java - 객체 생성 (0) | 2016.03.03 |
Java Reference와 GC (0) | 2016.02.29 |