κ·μΉ8 : μ’ λ£μ μ¬μ©μ νΌνλΌ
κ·μΉ8 : μ’ λ£μ μ¬μ©μ νΌνλΌ κ΄λ ¨
Avoid finalizers and cleaners
μ’
λ£μ(finalizer
) μ¬μ©μ μμΈ‘ν μ μκ³ μ’
μ’
μννκ³ μΌλ°μ μΌλ‘ νμμλ€. μ’
λ£μλ₯Ό μ¬μ©νλ©΄ μμ€ν
μ€λ₯, μ±λ₯ λ¬Έμ , μ΄μμ± λ¬Έμ κ° λ°μν μ μλ€.
Info
As of Java 9, finalizers have been deprecated, but they are still being used by the Java libraries. The Java 9 replacement for finalizers is cleansers. Cleaners are less dangerous than finalizers, but still unpredictable, slow, and generally unnecessary.
μλ° 9λΆν° finalizersλ deprecatedλμ§λ§, μ¬μ ν μλ° λΌμ΄λΈλ¬λ¦¬λ€μ΄ μ¬μ©μ€μ΄λ€. μλ° 9μμλ finalizers λμ cleanersλ‘ λ체λλ€. cleanersλ finalizers보λ€λ λ μννμ§λ§, μ¬μ ν μμΈ‘ν μ μκ³ λλ¦¬κ³ μΌλ°μ μΌλ‘ λΆνμνλ€.
C++μμ μλ©Έμλ κ°μ²΄μ λ°°μ λ μμμ λ°ννλ μΌλ°μ μΈ μλ¨μ΄λ©°, μμ±μμ μμΌλ‘ μ‘΄μ¬ν΄μΌ νλ€. νμ§λ§ μλ°μμλ GCκ° μμμ λ°ννλ―λ‘ νλ‘κ·Έλλ¨Έκ° νΉλ³ν ν μΌμ΄ μλ€. C++μμ μλ©Έμλ λ©λͺ¨λ¦¬ μ΄μΈμ μμμ λ°ννλ λ°λ μ¬μ©λλλ°, μλ°μμλ λ³΄ν΅ try-with-resources λ try-finally λΈλ‘μ΄ κ·Έλ° μ©λλ‘ μ¬μ©λλ€.
μ’ λ£μμ ν κ°μ§ λ¨μ μ, μ¦μ μ€νλ리λΌλ 보μ₯μ΄ μ ν μλ€λ κ²μ΄λ€. μ΄λ€ κ°μ²΄μ λν λͺ¨λ μ°Έμ‘°κ° μ¬λΌμ§κ³ λμ μ’ λ£μκ° μ€νλκΈ°κΉμ§λ κΈ΄ μκ°μ΄ 걸릴 μλ μλ€. λ°λΌμ κΈ΄κΈν(time-critical) μμ μ μ’ λ£μ μμμ μ²λ¦¬νλ©΄ μ λλ€. μλ₯Ό λ€μ΄ μ’ λ£μ μμμ νμΌμ λ«λλ‘ νλ©΄ μΉλͺ μ μ΄λ€. νμΌ κΈ°μ μ(file descriptor)λ μ νν μμμ΄κΈ° λλ¬Έμ΄λ€. JVMμ μ’ λ£μλ₯Ό μ²μ²ν μ€ννλ―λ‘ μ΄λ¦° μνμ νμΌμ΄ λ§μ΄ λ¨μ μμ μ μλ€. κ·Έλ° μν©μμ μλ‘μ΄ νμΌμ μ΄λ €κ³ νλ©΄, ν λ²μ μ΄ μ μλ νμΌμ κ°μμ μ νμ΄ μμΌλ―λ‘ μ€λ₯κ° λκ² λλ€.
κ·Έλ¦¬κ³ finalizers μ cleaners μ€ν μμ μ GC μκ³ λ¦¬μ¦ κ΅¬νμ λ°λΌ λ€μνλ€. κ·Έλμ JVMμ λ°λΌ λμμ΄ λ¬λΌμ§ μ μκΈ° λλ¬Έμ μ΄μμ± λ¬Έμ κ° λ°μν μ μλ€. λν μλ° μΈμ΄ λͺ μΈμμλ μ΄λ€ μ€λ λκ° μ’ λ£μλ₯Ό μ€νν΄μΌ νλμ§ μ무 μΈκΈλ μμΌλ―λ‘ μ΄μμ±(portability)μ 보μ₯νλ©΄μ μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν λ°©λ²μ μλ€. μ’ λ£μ μ¬μ©μ νΌνλ κ²λ§μ΄ μ μΌν κΈΈμ΄λ€.
Info
There is no portable way to prevent this sort of problem other than to refrain from using finalizers. Cleaners are a bit better than finalizers in this regard because class authors have control over their own cleaner threads, but cleaners still run in the background, under the control of the garbage collector, so there can be no guarantee of prompt cleaning.
μλ° λͺ μΈμμλ μ΄λ μ€λ λκ° finalizersλ₯Ό μ€νμν€λκ±Έ 보μ₯νμ§ μμλ€. κ·Έλμ finalizersλ₯Ό μμ°λ κ² λ§κ³ portableνκ² ν μ μλ€.Cleanersλ μ‘°κΈ λμλ° class authorsκ° μμ μ cleaner μ€λ λλ₯Ό μ μ΄ν μ μκΈ° λλ¬Έμ΄λ€. νμ§λ§ cleanersλ μ¬μ ν λ°±κ·ΈλΌμ΄λμμ gc μ μ΄λ‘ λκΈ° λλ¬Έμ μ¦μ μ€νμ 보μ₯μ΄ μλ€.
μλ° λͺ μΈλ μ’ λ£μκ° μ¦μ μνλμ΄μΌ νλ€λ 문ꡬλ μμ§λ§, μ’ λ£μκ° κ²°κ΅μλ λ°λμ μ€νλμ΄μΌ νλ€λ 문ꡬλ μλ€. λ°λΌμ μ’ λ£μκ° μ€νλμ§ μμ κ°μ²΄κ° λ¨μ μνλ‘ νλ‘κ·Έλ¨μ΄ λλκ² λλ μΌλ μΆ©λΆν κ°λ₯νλ€. κ·Έλ¬λ―λ‘ μ§μμ±μ΄ 보μ₯λμ΄μΌ νλ μ€μ μν μ 보(critical persistent state)λ μ’ λ£μλ‘ κ°±μ νλ©΄ μλλ€.
Info
As a consequence, you should never depend on a finalizer or cleaner to update persistent state. for example, depending on a finalizer or cleaner to release a persistent lock on a shared resource such as a database is a good way to bring your entire distributed system to a grinding halt.
persistent state updateλ finalizer λ cleanerμ μμ‘΄ν΄μλ μλλ€. λΆμ°μμ€ν μ 체λ₯Ό λ¨Ήν΅μΌλ‘ λ§λλ κ°μ₯ μ’μ λ°©λ²μ, dbκ°μ 곡μ μμμ λν persistent lockμ μ’ λ£μκ° λ°ννκ² κ΅¬ννλ κ²μ΄λ€.
@Override
protected void finalize() throws Throwable {
super.finalize();
// μ¬κΈ°μ persistent lockμ λ°ννκ² κ΅¬ν
}
System.gc
λ System.runFinalization
κ°μ λ©μλμ λ§μμ΄ νλ€λ¦¬λ©΄ κ³€λνλ€. μ΄λ° λ©μλλ€μ μ’
λ£μκ° μ€νλ κ°λ₯μ±μ λμ¬μ£ΌκΈ΄ νμ§λ§ 보μ₯νμ§ μλλ€. μ’
λ£μ μ€νμ 보μ₯νλ λ©μλλ€μ System.runFinalizersOnExit
μ Runtime.runFinalizersOnExit
λΏμΈλ°, μ΄λ€ λ©μλλ μ¬κ°ν κ²°ν¨μ κ°κ³ μμ΄μ μ΄λ―Έ λͺ
μΈμμ νκΈ°λμλ€.
λλ€λ₯Έ λ¬Έμ λ μ’ λ£ μ²λ¦¬ λμ€μ 무μ κ² μμΈκ° λμ Έμ§λ©΄, ν΄λΉ μμΈλ 무μλλ©° μ’ λ£ κ³Όμ μ μ€λ¨λλ€. μ΄λ° μμΈλ κ°μ²΄μ μνλ₯Ό λ§κ°λ¨λ¦΄ μ μλ€. μΌλ°μ μΌλ‘λ 무μ κ² μμΈκ° λ°μνλ©΄ μ€λ λλ μ’ λ£λκ³ μ€ν μΆμ μ λ³΄κ° νμλμ§λ§ μ’ λ£μ μμμλ μλλ€. κ²½κ³ λ¬Έκ΅¬μ‘°μ°¨ μΆλ ₯λμ§ μλλ€.
@Override
protected void finalize() throws Throwable {
super.finalize();
if ( ) {
} else {
throw new BongException();
}
}
Info
Cleaners do not have this problem because a library using a cleaner has control over its thread.
Cleanersλ μ΄ λ¬Έμ λ₯Ό κ°κ³ μμ§ μμλ° cleanerλ₯Ό μ¬μ©νλ λΌμ΄λΈλ¬λ¦¬κ° κ·Έ μ€λ λλ₯Ό μ μ΄νκΈ° λλ¬Έμ΄λ€.
κ·Έλ¦¬κ³ μ’ λ£μλ₯Ό μ¬μ©νλ©΄ μ±λ₯μ΄ μ¬κ°νκ² λ¨μ΄μ§λ€. νμμ μ»΄ν¨ν°μμ μΌλ° AutoCloseable κ°μ²΄λ₯Ό λ§λ€κ³ try-with-resourcesλ₯Ό μ΄μ©ν΄ close μν¬ λλ GCμ λ°ννλλ° 12nsκ° κ±Έλ Έλ€. finalizerλ₯Ό μ¬μ©νλ©΄ 550nsλ‘ μ¦κ°νλ€. μλνλ©΄ μ’ λ£μκ° GC ν¨μ¨μ±μ μ΅μ μν€κΈ° λλ¬Έμ΄λ€.
Info
Cleaners are comparable in speed to finalizers if you use them to clean all instances of the class (about 500 ns per instance on my machine), but cleaners are much faster if you use them only as a safety net, as discussed below. Under these circumstances, creating, cleaning, and destroying an object takes about 66 ns on my machine, which means you pay a factor of five (not fifty) for the insurance of a safety net if you don't use it.
Cleanersλ λͺ¨λ ν΄λμ€ μΈμ€ν΄μ€λ₯Ό cleanνλ€κ³ νμ λ μ½ 500nsλ‘ finalizerμ μλκ° λΉμ·νλ€. νμ§λ§ μμ λ§μμλ§ μ¬μ©νλ€λ©΄ 66nsλ‘ ν¨μ¬ λΉ¨λΌμ§λ€.
Info
Finalizers have a serious security problem: they open your class up to finalizer attacks.
Finalizer Attactμ λν μ€λͺ
μ΄ μ± μμλ finalizer attackμ λν μ€λͺ μ΄ μμΈνμ§ μμμ μμ λ°λ‘ μμΈν μ€λͺ ν¨.
(2rd edition λ΄μ©)
κ·Έλ λ€λ©΄ νμΌμ΄λ μ€λ λμ²λΌ λͺ μμ μΌλ‘ λ°ννκ±°λ μμ ν΄μΌ νλ μμμ ν¬ν¨νλ κ°μ²΄μ ν΄λμ€λ μ΄λ»κ² μμ±ν΄μΌ νλ κ²μΌκΉ?
κ·Έλ₯ λͺ
μμ μΈ μ’
λ£ λ©μλ(termination method)λ₯Ό νλ μ μνκ³ , λ μ΄μ νμνμ§ μλ κ°μ²΄λΌλ©΄ ν΄λΌμ΄μΈνΈκ° ν΄λΉ λ©μλλ₯Ό νΈμΆνλλ‘ νλΌ. ν κ°μ§ λͺ
μ¬ν κ²μ μ’
λ£ μ¬λΆλ₯Ό κ°μ²΄ μμ 보κ΄ν΄μΌ νλ€λκ². μ¦, μ ν¨νμ§ μμ κ°μ²΄μμ νμνλ private
νλλ₯Ό νλ λκ³ , λͺ¨λ λ©μλ 맨 μμ ν΄λΉ νλλ₯Ό κ²μ¬νλ μ½λλ₯Ό λμ΄ μ΄λ―Έ μ’
λ£λ κ°μ²΄μ λ©μλλ₯Ό νΈμΆνλ©΄ IllegalStateException
μ΄ λμ Έμ§λλ‘ ν΄μΌ νλ€λ κ²μ΄λ€. μ΄λ° λͺ
μμ μ’
λ£ λ©μλμ μλ‘λ OutputStream
μ΄λ InputStream
, java.sql.Connection
μ μ μλ close λ©μλκ° μλ€.
μ΄λ° λͺ
μμ μ’
λ£ λ©μλλ λ³΄ν΅ try
-finally
λ¬Έκ³Ό ν¨κ» μ°μΈλ€. κ°μ²΄ μ’
λ£λ₯Ό 보μ₯νκΈ° μν΄μλ€. λͺ
μμ μ’
λ£ λ©μλλ₯Ό finally
λ¬Έ μμμ νΈμΆνλλ‘ ν΄ λμΌλ©΄ κ°μ²΄ μ¬μ© κ³Όμ μμ μμΈκ° λμ Έμ Έλ μ’
λ£ λ©μλκ° μ€νλλλ‘ λ§λ€ μ μλ€.
μ’
λ£μκ° μ ν©ν κ³³μ΄ λ κ΅°λ° μ λ μλλ° νλλ, λͺ
μμ μ’
λ£ λ©μλ νΈμΆ(close
)μ μμ κ²½μ°μ λλΉνλ μμ λ§μΌλ‘μμ μν μ΄λ€. νμ§λ§ μ’
λ£μλ κ·Έλ° μμμ λ°κ²¬νκ² λ κ²½μ° λ°λμ κ²½κ³ λ©μμ§λ₯Ό λ‘κ·Έλ‘ λ¨κ²¨μΌ νλ€.
λͺ
μμ μ’
λ£ λ©μλ ν¨ν΄μ λ°λ₯΄λ μλ‘ λ€μλ λ€ κ°μ§ ν΄λμ€λ€(FileInputStream
, FileOutputStream
, Timer
, Connection
)μ μ’
λ£ λ©μλκ° νΈμΆλμ§ μμ κ²½μ°μ λλΉνμ¬ μ’
λ£μ μμ λ§μ κ°μΆκ³ μλ€. λΆννλ μ΄λ€ μ’
λ£μλ κ²½κ³ λ‘κ·Έλ₯Ό λ¨κΈ°μ§ μλλ€. APIκ° κ³΅κ°λ λ€μμλ κ·Έλ° κΈ°λ₯μ μΆκ°νλ κ²μ΄ μΌλ°μ μΌλ‘ λΆκ°λ₯νλ°, μ΄λ―Έ μμ±λ ν΄λΌμ΄μΈνΈ μ½λλ₯Ό κΉ¨λ¨λ¦¬κ² λ κ²μ΄κΈ° λλ¬Έμ΄λ€.
λ λ²μ§Έ κ²½μ°λ λ€μ΄ν°λΈ νΌμ΄(native peer)μ μ°κ²°λ κ°μ²΄λ₯Ό λ€λ£° λλ€. λ€μ΄ν°λΈ νΌμ΄λ μΌλ° μλ° κ°μ²΄κ° λ€μ΄ν°λΈ λ©μλλ₯Ό ν΅ν΄ κΈ°λ₯ μνμ μμνλ λ€μ΄ν°λΈ κ°μ²΄λ₯Ό λ§νλ€. λ€μ΄ν°λΈ νΌμ΄λ μΌλ° κ°μ²΄κ° μλλ―λ‘ gcκ° μ μ μμ λΏλλ¬ μλ° μΈ‘ νΌμ΄ κ°μ²΄(java peer)κ° λ°νλ λ κ°μ΄ λ°νν μλ μλ€. λ€μ΄ν°λΈ νΌμ΄κ° μ€μν μμμ μ μ νκ³ μμ§ μλ€κ³ κ°μ νλ€λ©΄, μ’ λ£μλ κ·Έλ° κ°μ²΄μ λ°νμ κ±Έλ§λ€. λ€μ΄ν°λΈ νΌμ΄κ° μ¦μ μ’ λ£λμ΄μΌ νλ μμμ ν¬ν¨νλ κ²½μ°μλ, μμ μ€λͺ ν λλ‘ λͺ μμ μΈ μ’ λ£ λ©μλλ₯Ό ν΄λμ€μ μΆκ°ν΄μΌ νλ€.
μμ κ°μ΄ μ’
λ£μλ₯Ό μ¬μ©ν΄μΌ νλ λλ¬Έ μν©μ μ²νλ€λ©΄ super.finalize νΈμΆμ μμ§ λ§μ. "μ’
λ£μ μ°κ²°(finalizer chaining)"μ΄ μλμΌλ‘ μ΄λ£¨μ΄μ§μ§ μλλ€. λ§μΌ (Object
κ° μλ) μ΄λ€ ν΄λμ€κ° μ’
λ£μλ₯Ό κ°κ³ μκ³ νμ ν΄λμ€κ° ν΄λΉ λ©μλλ₯Ό μ¬μ μνλ κ²½μ°, νμ ν΄λμ€μ μ’
λ£μλ μμ ν΄λμ€μ μ’
λ£μλ₯Ό λͺ
μμ μΌλ‘ νΈμΆν΄μΌ νλ€. μ΄λ νμ ν΄λμ€μ μνλ try λΈλ‘ μμμ μ’
λ£μμΌμΌ νκ³ , μμ ν΄λμ€ μ’
λ£μλ finally λΈλ‘ μμμ νΈμΆν΄μΌ νλ€. κ·ΈλμΌ νμ ν΄λμ€μ μ’
λ£ κ³Όμ μμ μμΈκ° λ°μν΄λ μμ ν΄λμ€ μ’
λ£μλ λ°λμ νΈμΆλλλ‘ ν μ μλ€.
// μλ μ’
λ£μ μ°κ²°
@Override
protected void finalize() throws Throwable {
try {
... // νμ ν΄λμ€μ μνλ₯Ό μ’
λ£ν¨
} finally {
super.finalize();
}
}
νμ ν΄λμ€μμ μμ ν΄λμ€ μ’ λ£μλ₯Ό μ¬μ μνλ©΄μ μμ ν΄λμ€ μ’ λ£μ νΈμΆμ μμΌλ©΄, μμ ν΄λμ€ μ’ λ£μλ μ λλ‘ νΈμΆλμ§ μλλ€. μ΄λ° λ©μ²ν νμ ν΄λμ€ λμ μκΈ°λ λ¬Έμ λ₯Ό λ°©μ§νλ ν κ°μ§ λ°©λ²μ, μ’ λ£λμ΄μΌ νλ λͺ¨λ κ°μ²΄λ§λ€ μ¬λ²μ κ°μ²΄λ₯Ό νλ λ λ§λλ κ²μ΄λ€. μ’ λ£λμ΄μΌ νλ κ°μ²΄μ ν΄λμ€ μμ μ’ λ£μλ₯Ό μ μνλ λμ , μ΅λͺ ν΄λμ€μμ μ’ λ£μλ₯Ό μ μνλ κ²μ΄λ€. μ΄ μ΅λͺ ν΄λμ€μ λͺ©μ μ ν΄λΉ ν΄λμ€μ κ°μ²΄λ₯Ό ν¬ν¨νλ κ°μ²΄λ₯Ό μ’ λ£μν€λ κ²μ΄λ€. μ΄ μ΅λͺ ν΄λμ€λ‘ λ§λ κ°μ²΄λ μ’ λ£ λ³΄νΈμλΌκ³ λΆλ₯΄λλ°, μ’ λ£λμ΄μΌ νλ κ°μ²΄ μμ νλμ© λ£λλ€. μ’ λ£ λ³΄νΈμμ λ°κΉ₯ κ°μ²΄μλ μ’ λ£ λ³΄νΈμλ₯Ό μ°Έμ‘°νλ private νλκ° μλ€. λ°λΌμ λ°κΉ₯ κ°μ²΄μ λν λͺ¨λ μ°Έμ‘°κ° μ¬λΌμ§λ μκ°, μ’ λ£ λ³΄νΈμμ μ’ λ£μλ μ€ν κ°λ₯ν μνκ° λλ€. μ΄ λ³΄νΈμ κ°μ²΄μ μ’ λ£μλ νμν μ’ λ£ μμ μ, λ§μΉ λ°κΉ₯ κ°μ²΄μ μ’ λ£μμΈ κ²μ²λΌ μννλ€.
// μ’
λ£ λ³΄νΈμ μμ΄
public class Foo {
// μ΄ κ°μ²΄λ λ°κΉ₯ κ°μ²΄(Foo κ°μ²΄)λ₯Ό μ’
λ£μν€λ μν λ§ νλ€.
private final Object finalizerGuardian = new Object() {
@Override
protected void finalize() throws Throwable {
... // λ°κΉ₯ Foo κ°μ²΄λ₯Ό μ’
λ£μν΄
}
};
... // μ΄ν μλ΅
}
public
ν΄λμ€ Foo
μλ μ’
λ£μκ° μλ€λ κ²μ μ μνμ(Object
μμ κ³μΉλ, 무μν΄λ μ’μ finalize λ©μλ λ§κ³€ μλ€). λ°λΌμ νμ ν΄λμ€μ μ’
λ£μκ° μμ ν΄λμ€μ μ’
λ£μλ₯Ό νΈμΆν건 λ§κ±΄ μκ΄ μλ€. μ΄ κΈ°λ²μ μ’
λ£μκ° μλ λΉ-final ν΄λμ€λ₯Ό ꡬνν λ λ°λμ κ³ λ €ν΄μΌ νλ€.
3rd edition λ΄μ©
κ·Έλ λ€λ©΄ νμΌμ΄λ μ€λ λμ²λΌ μμ ν΄μΌ νλ μμμ ν¬ν¨νλ κ°μ²΄μ ν΄λμ€λ μ΄λ»κ² μμ±ν΄μΌ νλ κ²μΌκΉ? ν΄λμ€μ AutoCloseable
μΈν°νμ΄μ€λ₯Ό ꡬνν΄μ λ μ΄μ νμμμ λ close() λ©μλλ₯Ό νΈμΆν΄λΌ (try-with-resourcesλ₯Ό μ¬μ©νλ©΄ exception λ°μμλ μ’
λ£κ° 보μ₯λλ€).
μΈκΈν κ°μΉκ° μλ νκ°μ§ μΈλΆ μ¬νμ μΈμ€ν΄μ€κ° λ«ν μλμ§ μ¬λΆλ₯Ό μΆμ ν΄μΌνλ€λ κ²μ΄λ€. close
λ©μλλ κ°μ²΄κ° λ μ΄μ μ ν¨νμ§ μμ νλλ₯Ό κΈ°λ‘ν΄μΌ νλ©° λ€λ₯Έ λ©μλλ μ΄ νλλ₯Ό κ²μ¬νμ¬ μ΄λ―Έ μ’
λ£λ κ°μ²΄μ λ©μλλ₯Ό νΈμΆνλ©΄ IllegalStateException
μ λ°μμμΌμΌ νλ€.
μ’
λ£μκ° μ ν©ν κ³³μ΄ λ κ΅°λ° μ λ μλλ° νλλ close λ©μλ νΈμΆμ μμ κ²½μ°μ λλΉνλ μμ λ§μΌλ‘μμ μν μ΄λ€. cleaner
λ finalizer
κ° μ¦μ λλ μ λΆ μ€νλλ€λ 보μ₯μ μμ§λ§, close
λ©μλλ₯Ό μμμ λ μ무κ²λ μνλ κ²λ³΄λ€λ(λ¦μ΄μ§λλΌλ) μλκ² λ«λ€. FileInputStream
, FileOutputStream
, ThreadPoolExecutor
, java.sql.Connection
μλ° λΌμ΄λΈλ¬λ¦¬λ€μ μμ λ§μΌλ‘μ¨ finalizer
λ₯Ό ꡬννκ³ μλ€.
λ λ²μ§Έ κ²½μ°λ λ€μ΄ν°λΈ νΌμ΄(native peer)μ μ°κ²°λ κ°μ²΄λ₯Ό λ€λ£° λλ€. λ€μ΄ν°λΈ νΌμ΄λ μΌλ° μλ° κ°μ²΄κ° λ€μ΄ν°λΈ λ©μλλ₯Ό ν΅ν΄ κΈ°λ₯ μνμ μμνλ λ€μ΄ν°λΈ κ°μ²΄λ₯Ό λ§νλ€. λ€μ΄ν°λΈ νΌμ΄λ μΌλ° κ°μ²΄κ° μλλ―λ‘ gcκ° μ μ μμ λΏλλ¬ μλ° μΈ‘ νΌμ΄ κ°μ²΄(java peer)κ° λ°νλ λ κ°μ΄ λ°νν μλ μλ€. λ€μ΄ν°λΈ νΌμ΄κ° μ€μν μμμ μ μ νκ³ μμ§ μλ€κ³ κ°μ νλ€λ©΄, μ’ λ£μλ κ·Έλ° κ°μ²΄μ λ°νμ κ±Έλ§λ€. λ€μ΄ν°λΈ νΌμ΄κ° μ¦μ μ’ λ£λμ΄μΌ νλ μμμ ν¬ν¨νλ κ²½μ°μλ, μμ μ€λͺ ν λλ‘ close λ©μλλ₯Ό ν΄λμ€μ μΆκ°ν΄μΌ νλ€.
Cleaners
λ μ¬μ©νκΈ°κ° μ½κ° κΉλ€λ‘λ€. μλ μ½λλ κ°λ¨ν Room ν΄λμ€λ€(room
μ΄ λ°νλκΈ° μ μ clean
λμΌ νλ€κ³ κ°μ νμ). Room
ν΄λμ€λ AutoCloseable
μΈν°νμ΄μ€λ₯Ό ꡬννλ€. automatic cleaning safety netμ΄ cleaner
λ₯Ό μ¬μ©νλ€λ μ¬μ€μ λ¨μ§ ꡬν μΈλΆ μ¬νμ΄λ€. finalizers
μ λ€λ₯΄κ² cleaners
λ ν΄λμ€μ public APIλ₯Ό μ€μΌμν€μ§ μλλ€.
// An autocloseable class using a cleaner as a safety net
public class Room implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
// Resource that requires cleaning. Must not refer to Room!
private static class State implements Runnable {
int numJunkPiles; // Number of junk piles in this room
State(int numJunkPiles) {
this.numJunkPiles = numJunkPiles;
}
// Invoked by close method or cleaner
@Override
public void run() {
System.out.println("Cleaning room");
numJunkPiles = 0;
}
}
// The state of this room, shared with our cleanable
private final State state;
// Our cleanable. Cleans the room when it's eligible for gc
private final Cleaner.Cleanable cleanable;
public Room(int numJunkPiles) {
state = new State(numJunkPiles);
cleanable = cleaner.register(this, state);
}
@Override
public void close() {
cleanable.clean();
}
}
μ€μ²©λ State static
ν΄λμ€λ clean
λ μμμ κ°κ³ μλ€. μμ κ²½μ° λ¨μν numJunkPiles
νλλ€(represents the amount of mess in the room). μ’ λ νμ€μ μ΄λΌλ©΄ native peerλ₯Ό κ°λ¦¬ν€λ ν¬μΈν°λ₯Ό κ°λ final longμ΄ λ κ²μ΄λ€.
State ν΄λμ€λ Runnable
μΈν°νμ΄μ€λ₯Ό ꡬννκ³ Room
μμ±μμμ State μΈμ€ν΄μ€λ₯Ό λ±λ‘ν λ Cleanable
μ ν΅ν΄μ run λ©μλκ° νλ²λ§ νΈμΆλλ€. run
λ©μλ νΈμΆμ λκ°μ§ μ€ νλμ μν΄ νΈλ¦¬κ±° λλ€. λ³΄ν΅ Room
μ close λ©μλμμ Cleanable
μ clean
λ©μλλ₯Ό νΈμΆν λ νΈλ¦¬κ±° λλ€. λ§μ½ Room
μΈμ€ν΄μ€κ° GC μ격μ μ»μ λκΉμ§ close
λ©μλκ° νΈμΆλμ§ μλλ€λ©΄, Cleaner
λ State
μ run
λ©μλλ₯Ό νΈμΆν κ²μ΄λ€ (hopefully).
State
μΈμ€ν΄μ€κ° Room
μΈμ€ν΄μ€λ₯Ό μ°Έμ‘°νμ§ μλκ²μ ν¬λ¦¬ν°μ»¬νλ€. λ§μ½ μ°Έμ‘°νλ€λ©΄, Room
μΈμ€ν΄μ€κ° GC μ격μ μ»λ κ²μ (κ·Έλ¦¬κ³ μλμΌλ‘ clean
λλ) λ§μμ£Όλ μνμ±μ μμ±νκ² λλ€. κ·Έλ¬λ―λ‘ State
ν΄λμ€λ λ°λμ μ€μ²©λ staic
ν΄λμ€μ¬μΌ νλ€. μλνλ©΄ non static μ€μ²© ν΄λμ€λ μμ μ λλ¬μΌ ν΄λμ€ μΈμ€ν΄μ€ μ°Έμ‘°λ₯Ό ν¬ν¨νκΈ° λλ¬Έμ΄λ€.
it is similarly inadvisable to use a lambda beacause they can easily capture references to enclosing objects.
Room cleanerλ μ€μ§ μμ λ§μΌλ‘ μ¬μ©λμΌ νλ€. λ§μ½ Room
κ°μ²΄ μμ±μ try-with-resource λΈλ‘μΌλ‘ κ°μλ€λ©΄, automatic cleaningμ μ λ νμνμ§ μλ€.
public class Adult {
public static void main(String[] args) {
try (Room myRoom = new Room(7)) {
System.out.println("Goodbye");
}
}
}
μμ κ°μ΄ μ€νμν€λ©΄ Cleaning room λ©μΈμ§μ ν¨κ» Goodbye
κ° μΆλ ₯λ κ²μ΄λ€. κ·Έλ¬λ μλμ κ°μ΄ μ€ννλ©΄ μ΄λ»κ² λ κΉ?
public class Teenager {
public static void main(String[] args) {
new Room(99);
System.out.println("Peace out");
}
}
Cleaning room λ©μΈμ§μ ν¨κ» Peace out
μ΄ μΆλ ₯λκΈΈ κΈ°λνκ² μ§λ§, Cleaning roomμ μΆλ ₯λμ§ μκ³ κ·Έλ₯ λλλ²λ¦°λ€. μ΄κ² μ μ μκΈ°νλ unpredictabilityμ΄λ€. Cleaner μ€νμ System.exit
μ€ ν΄λ¦¬λμ λμμ ꡬνμ λ°λΌ λ€λ₯΄λ€κ³ λ§νλ€. cleaning actionμ λν 보μ₯μ΄ μλ€. νμκ° System.gc()λ₯Ό μΆκ°νλλ λλκΈ° μ μ Cleaning roomμ μΆλ ₯νλ€. κ·Έλ¬λ μ°λ¦¬κ° μ€ννμ λ κ·Έκ² λ°λμ κ·Έλ κ² λλ€λ 보μ₯μ΄ μλ€.