JavaにおけるSoftReferenceとWeakReferenceの違い
SoftReferenceとWeakReferenceの違い
GC対象となるオブジェクト
SoftReferenceとWeakReferenceは、どちらもGCの対象となるオブジェクトへの参照を保持します。つまり、GCが実行されると、参照されているオブジェクトがメモリ不足などの理由で開放される可能性があります。
GC時の参照の扱い
SoftReference:
- ただし、オブジェクトへの参照がまだ存在している場合、またはメモリに余裕がある場合は、オブジェクトは開放されずに保持されます。
- SoftReferenceは、メモリ不足になる前にオブジェクトを解放したい場合に使用されます。
- オブジェクトへの参照がまだ存在している場合でも、オブジェクトはGCの対象となり、開放されます。
- WeakReferenceは、オブジェクトがGC対象であることを明確に示したい場合に使用されます。
メモリリーク
SoftReferenceとWeakReferenceは、メモリリークを防ぐために使用できます。
- SoftReference: メモリ不足になる前にオブジェクトを解放することで、メモリリークを防ぐことができます。
- WeakReference: オブジェクトへの参照が不要になった時点でオブジェクトが解放されるようにすることで、メモリリークを防ぐことができます。
使用例
- 画像キャッシュ: 画像キャッシュでは、メモリ不足になる前に古い画像を解放するためにSoftReferenceを使用できます。
- 最近使用されたオブジェクトのリスト: 最近使用されたオブジェクトのリストでは、オブジェクトが使用されなくなった時点でリストから削除するためにSoftReferenceを使用できます。
- イベントリスナー: イベントリスナーは、イベント発生時に呼び出されるオブジェクトです。WeakReferenceを使用してイベントリスナーへの参照を保持することで、イベントリスナーが不要になった時点で解放されるようにできます。
- オブジェクトへの弱い参照: オブジェクトへの弱い参照を作成することで、オブジェクトがGC対象であることを明確に示すことができます。
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
public class Main {
public static void main(String[] args) {
// SoftReference のサンプル
SoftReference<Object> softReference = new SoftReference<>(new Object());
System.out.println("SoftReference: " + softReference.get());
// メモリ不足をシミュレート
for (int i = 0; i < 100000; i++) {
new Object();
}
System.out.println("SoftReference: " + softReference.get()); // メモリ不足によっては null になる
// WeakReference のサンプル
WeakReference<Object> weakReference = new WeakReference<>(new Object());
System.out.println("WeakReference: " + weakReference.get());
// GC を実行
System.gc();
System.out.println("WeakReference: " + weakReference.get()); // GC 後は必ず null になる
}
}
- SoftReferenceは、メモリ不足になる前にオブジェクトを解放しますが、オブジェクトへの参照がまだ存在している場合やメモリに余裕がある場合は保持されます。
- WeakReferenceは、オブジェクトへの参照が不要になった時点でオブジェクトが解放されます。
実行例:
SoftReference: java.lang.Object@7f3201d8
SoftReference: null
WeakReference: java.lang.Object@5b126337
WeakReference: null
この例では、GCを実行した後、WeakReferenceはnullになっていますが、SoftReferenceはnullになる場合とそうでない場合があります。
- WeakReferenceは、オブジェクトへの参照が不要になった時点でオブジェクトが解放されますが、オブジェクトへの参照がまだ存在している場合でもGCによって解放される可能性があります。
これらの制限を克服するために、いくつかの代替方法があります。
ファイナライザ
ファイナライザは、オブジェクトがGCされる前に呼び出されるメソッドです。ファイナライザを使用して、オブジェクトが不要になったときにリソースを解放することができます。
public class MyClass {
@Override
protected void finalize() throws Throwable {
// リソースを解放する
super.finalize();
}
}
ただし、ファイナライザはGCのタイミングに影響を与えるため、使用には注意が必要です。
オブジェクトプール
オブジェクトプールは、再利用可能なオブジェクトのプールです。オブジェクトプールを使用することで、オブジェクトの作成と破棄を管理することができます。
public class ObjectPool {
private List<Object> pool = new ArrayList<>();
public Object borrow() {
synchronized (pool) {
if (pool.isEmpty()) {
return new Object();
} else {
return pool.remove(0);
}
}
}
public void return(Object object) {
synchronized (pool) {
pool.add(object);
}
}
}
オブジェクトプールは、オブジェクトの作成と破棄のコストを削減するために使用できます。
キャッシュ
キャッシュは、頻繁にアクセスされるオブジェクトを保存するために使用されます。キャッシュを使用することで、オブジェクトへのアクセス速度を向上させることができます。
public class Cache {
private Map<String, Object> cache = new HashMap<>();
public Object get(String key) {
synchronized (cache) {
return cache.get(key);
}
}
public void put(String key, Object object) {
synchronized (cache) {
cache.put(key, object);
}
}
}
キャッシュは、オブジェクトへのアクセス頻度が高い場合に使用できます。
弱参照エントリ
Java 9以降では、java.lang.ref.WeakReferenceEntry
クラスを使用して、弱参照エントリを作成することができます。弱参照エントリは、弱参照と関連付けられた追加情報を保持することができます。
public class Main {
public static void main(String[] args) {
// 弱参照エントリを作成
WeakReferenceEntry<Object> entry = new WeakReferenceEntry<>(new Object(), "key");
// 弱参照エントリからオブジェクトを取得
Object object = entry.get();
// 弱参照エントリに関連付けられた情報を取得
String key = entry.getKey();
}
}
弱参照エントリは、弱参照と関連付けられた情報を保持する必要がある場合に使用できます。
SoftReferenceとWeakReferenceは、オブジェクトへの弱い参照を作成するための便利な方法ですが、いくつかの制限があります。これらの制限を克服するために、ファイナライザ、オブジェクトプール、キャッシュ、弱参照エントリなどの代替方法を使用することができます。
java reference weak-references