#今日から始める!弱い参照
java.lang.ref
パッケージに入っているReferenceインターフェイスとその3つの実装WeakReference,SoftReference,PhantomReference。今日は手始めにWeakReferenceについて見てみます。
package references;
public class Sheryl {
public void sing(){
System.out.println("生き残りたい");
}
}
package references;
import java.lang.ref.*;
public class Main {
public static void main(String[] args) {
Sheryl strongRef = new Sheryl();//①
WeakReference<Sheryl> weakRef = new WeakReference<Sheryl>(strongRef);//②
strongRef = null;//③
Sheryl sheryl = weakRef.get();
if (sheryl != null){
System.out.println("まだ生きてます");
sheryl.sing();
}else{
System.out.println("消えました");
}
sheryl = null;
System.gc();//④
System.out.println("GCしました");
Sheryl sheryl = weakRef.get();
if (sheryl != null){
System.out.println("まだ生きてます");
sheryl.get().sing();
}else{
System.out.println("消えました");
}
}
}
① Sherylのオブジェクトを通常通り生成(これが強参照と呼ばれる参照)
② 上記のオブジェクトに対し、弱参照も生成
(Sherylオブジェクトに対し強と弱の2参照がついたことになる)
③ 強参照の方だけ削除、弱参照のみとなる
(※参照を消しただけでオブジェクトは消えていないYO!)
④ Sherylオブジェクトは弱参照しか持ってないのでGC(ガベージコレクト)に回収される
まだ生きてます
生き残りたい
GCしました
消えました
3.の時点では強参照が消え、弱参照だけが残っています。弱参照を使えばSherylオブジェクトにたどり着くことはできます。こういったオブジェクトのことを「弱到達が可能なオブジェクト」と呼ぶそうです。
このオブジェクトはGCが来た場合に消されてしまいます。実際、4.以降は弱参照のオブジェクトを通してもSherylオブジェクトにたどり着くことはできなくなってしまいました。
強参照が残っている場合はなんともないのですが、弱参照のみになってからが独特です。GCが来るまではアクセスできるけど、GCが来たら消えてしまう、というなんとも儚いオブジェクトになってしまうのです。
#どこで使うの…?
弱参照が張られているだけではいつGCされるかわかりません。なので、弱参照だけで運用することはなく、強参照と組み合わせて運用するとメリットが生まれてくると思われます。
メリットというのは、強参照がなくなったらそれに呼応するようにGCされるようにできるってこと。ある意味、強参照がなくなったよという通知を受け、その通知の結果、自分自身も消える、という処理を行っているようなイメージ。
これにより、オブジェクトの消し忘れ、つまりメモリリークを防ぐ一端を担うことができます。
##具体的には…
⇨WeakHashMapで使われています。
WeakHashMapではkeyを弱参照で保持するので、このMap以外にそのキーを参照するものがなくなると、GCされます。ついでに組になってるvalueも消しちゃいます。
別にいらないけどできればとっておきたい、というキャッシュみたいなオブジェクトを保持するのに良さそうです。
HashMapを使って管理はしたいんだけども、管理対象のライフサイクルまで把握しきれないよ、っていうときに使えそうです。管理対象がなくなればそのMapから消えてくれても全然構わんし、という。
参考:Java弱参照メモ(Hishidama's Java Weak reference Memo)
#SoftReferenceとWeakReferenceってどう違うの…?
SoftReferenceも強参照に比べ弱い参照です。WeakReferenceのオブジェクトは、弱到達可能になったらGCのタイミングで迷わず消されますが、SoftReferenceのオブジェクトは、ソフト到達可能になっても、GCが来たからと言って必ず消されるわけではない、という違いがあるらしいです。
参考:Javaの理論と実践: ソフト参照でメモリー・リークを塞ぐ
あるオブジェクトに対して残っている参照が、弱参照あるいはソフト参照のみである場合、そのオブジェクトは『ソフト到達可能(softly reachable)』と言われます。ガーベジ・コレクターは、弱到達可能(weakly reachable)オブジェクトを収集するほど積極的には、ソフト到達可能オブジェクトを収集しません。ガーベジ・コレクターは、本当にメモリーを「必要とする」場合のみ、ソフト到達可能オブジェクトを収集するのです。ソフト参照は、ガーベジ・コレクターに対して、「メモリーが非常に不足しているのでない限り、私はこのオブジェクトを保持しておきたい。しかしメモリーが非常に不足しているのであれば、どうぞ収集してください。私はそれに応じて何とかします」と言うための方法なのです。ガーベジ・コレクターは、OutOfMemoryErrorエラーを投げる前には、すべてのソフト参照をクリアーする必要があります。
#まとめ
参照ってそんなに種類あったんですね…。わしゃ知らんかったよ!Phantomについてはまた今度見てみます。