본문으로 바로가기
반응형

Weak reference와 soft reference는 그래도 뒤져보면 예제가 좀 있습니다.

하지만 정말 rare하게 쓰이는 phantom reference에 대한 예제는 구글링을 해도 찾기가 쉽지 않습니다.

다행이 아래 깔끔한 예제를 찾았기에 링크 해 봅니다.

원문은 아래 링크에서 확인하실 수 있습니다.

http://neverfear.org/blog/view/150/Strong_Soft_Weak_and_Phantom_References_Java


Strong References

먼저 우리가 일반적으로 쓰고있는 Strong reference 입니다.
이런식의 참조는 절대 GC가 되지 않습니다.
package org.neverfear.leaks;
 
/*
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassStrong {
 
    public static class Referred {
        protected void finalize() {
            System.out.println("Good bye cruel world");
        }
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating strong references");
 
        // This is now a strong reference.
        // The object will only be collected if all references to it disappear.
        Referred strong = new Referred();
 
        // Attempt to claim a suggested reference.
        ClassStrong.collect();
 
        System.out.println("Removing reference");
        // The object may now be collected.
        strong = null;
        ClassStrong.collect();
 
        System.out.println("Done");
    }
 
}


Soft references

이 경우 JVM은 메모리가 없을 경우 GC가 됩니다. 따라서 원문에서는 캐쉬(cache)로 사용하면 좋다고 언급하지만, 사실 soft reference는 캐쉬로 사용하면 안됩니다. 그 상세한 이유는 나중에 JVM 메모리에 대한 주제로 다룰때 언급하겠습니다.
다만 간략하게 설명하자면 soft reference로 인해 메모리에 GC threshold 까지 계속 차있는 상태가 유지되면서 훨씬더 잦은 GC를 발생시킵니다.
그리고 안드로이드 같이 강력하게 GC에 대응하도록 구성된 경우에는 weak reference와 동작하는게 크게 다르지 않습니다.
메모리가 적은 모바일 기기 특성상 그냥 다 GC 시켜버리는 거죠..
package org.neverfear.leaks;
 
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
 
/*
 * A sample for Detecting and locating memory leaks in Java
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassSoft {
 
    public static class Referred {
        protected void finalize() {
            System.out.println("Good bye cruel world");
        }
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating soft references");
 
        // This is now a soft reference.
        // The object will be collected only if no strong references exist and the JVM really needs the memory.
        Referred strong = new Referred();
        SoftReference<Referred> soft = new SoftReference<Referred>(strong);
 
        // Attempt to claim a suggested reference.
        ClassSoft.collect();
 
        System.out.println("Removing reference");
        // The object may but highly likely wont be collected.
        strong = null;
        ClassSoft.collect();
 
        System.out.println("Consuming heap");
        try
        {
            // Create lots of objects on the heap
            List<ClassSoft> heap = new ArrayList<ClassSoft>(100000);
            while(true) {
                heap.add(new ClassSoft());
            }
        }
        catch (OutOfMemoryError e) {
            // The soft object should have been collected before this
            System.out.println("Out of memory error raised");
        }
 
        System.out.println("Done");
    }
 
}


Weak references

가장 흔하게 쓰는 reference 입니다.
명시적으로 weak reference를 사용함으로써 해당객체가 GC 되도록 유도할 수 있습니다.
package org.neverfear.leaks;
 
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
 
/*
 * A sample for Detecting and locating memory leaks in Java
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassWeak {
 
    public static class Referred {
        protected void finalize() {
            System.out.println("Good bye cruel world");
        }
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating weak references");
 
        // This is now a weak reference.
        // The object will be collected only if no strong references.
        Referred strong = new Referred();
        WeakReference<Referred> weak = new WeakReference<Referred>(strong);
 
        // Attempt to claim a suggested reference.
        ClassWeak.collect();
 
        System.out.println("Removing reference");
        // The object may be collected.
        strong = null;
        ClassWeak.collect();
 
        System.out.println("Done");
    }
 
}


Phantom references

거의 쓰지 않지만 그래도 알아두면 유용한 팬텀 레퍼런스 입니다.
예제도 사실 거의 없습니다.
이 녀석의 용도는 finalize()를 대체 하는 방법으로 사용하는데 이는 object가 resurrect 될수 있기 때문입니다.
그 밖에도 finalize()의 문제가 많은데, 그건 나중에 reference에 대한 전반적인 정리를 할때 다루도록 하겠습니다.

그리고 팬텀레퍼런스 사용시에는 레퍼런스큐(reference queue)의 사용은 필수적입니다.
weak, soft에서는 option입니다.
package org.neverfear.leaks;
 
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
import java.util.Map;
 
/*
 * A sample for Detecting and locating memory leaks in Java
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassPhantom {
 
    public static class Referred {
        // Note that if there is a finalize() method PhantomReference's don't get appended to a ReferenceQueue
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating phantom references");
 
        // The reference itself will be appended to the dead queue for clean up.
        ReferenceQueue dead = new ReferenceQueue(); 
 
        // This map is just a sample we might use to locate resources we need to clean up.
        Map<Reference,String> cleanUpMap = new HashMap<Reference,String>();
 
        // This is now a phantom reference.
        // The object will be collected only if no strong references.
        Referred strong = new Referred();
 
        PhantomReference<Referred> phantom = new PhantomReference(strong, dead);
        cleanUpMap.put(phantom, "You need to clean up some resources, such as me!");
 
        strong = null;
 
        // The object may now be collected
        ClassPhantom.collect();
 
        // Check for 
        Reference reference = dead.poll();
        if (reference != null) {
            System.out.println(cleanUpMap.remove(reference));
        }
        System.out.println("Done");
    }
 
}


WeakHashMap

weak reference를 써서 메모리에 좀 신경썼다 하더라도 hashmap으로 잡혀있는 경우가 꽤 있습니다.
따라서 이런 경우를 위해 WeakHashMap이 따로 구현되어 있습니다.
뭐..직접 weak reference를 갖는 hashMap을 만들어 써도 되지만요.
package org.neverfear.leaks;
 
import java.util.Map;
import java.util.WeakHashMap;
 
/*
 * A sample for Detecting and locating memory leaks in Java
 * URL: http://neverfear.org/blog/view/150/Java_References
 * Author: doug@neverfear.org
 */
public class ClassWeakHashMap {
 
    public static class Referred {
        protected void finalize() {
            System.out.println("Good bye cruel world");
        }
    }
 
    public static void collect() throws InterruptedException {
        System.out.println("Suggesting collection");
        System.gc();
        System.out.println("Sleeping");
        Thread.sleep(5000);
    }
 
    public static void main(String args[]) throws InterruptedException {
        System.out.println("Creating weak references");
 
        // This is now a weak reference.
        // The object will be collected only if no strong references.
        Referred strong = new Referred();
        Map<Referred,String> metadata = new WeakHashMap<Referred,String>();
        metadata.put(strong, "WeakHashMap's make my world go around");
 
        // Attempt to claim a suggested reference.
        ClassWeakHashMap.collect();
        System.out.println("Still has metadata entry? " + (metadata.size() == 1));
        System.out.println("Removing reference");
        // The object may be collected.
        strong = null;
        ClassWeakHashMap.collect();
 
        System.out.println("Still has metadata entry? " + (metadata.size() == 1));
 
        System.out.println("Done");
    }
 
}



반응형

'개발이야기 > Java' 카테고리의 다른 글

Java의 동기화 Synchronized 개념 정리#2  (7) 2017.11.20
Java의 동기화 Synchronized 개념 정리#1  (20) 2017.11.19
Weak reference의 이해  (1) 2017.10.22
람다의 내부동작 #2  (0) 2017.09.26
람다의 내부동작 #1  (0) 2017.09.24