정말 좋은 자료라 퍼왔습니다.


이미지 캐싱에는 정말 많은 문제가 있는데 SoftReference 를 활용한 방법도 좋은 해결책이 될 것 같습니다.


==============================================================================================================================


저는 자바로 어플리케이션 개발을 시작한지 이제 일년 남짓 되었습니다(아직 멀었지요). 때문에, 자바에서 제공해주는 무지무지 강력한 기본 라이브러리들을 활용하는 방법을 모르고 있다가, 한참을 끙끙거리고 누덕 누덕하게 코드를 짰더니, 알고보니 자바에서는 그냥 되는거네... 하고 허탈해하던 경험이 종종 있습니다. (음악 플레이리스트의 셔플 기능 관련해서, 두어시간을 작업해두었더니 알고보니 자바 리스트에는 기본으로 셔플기능이 지원하더라... 같은 슬픈 이야기이지요.) 


 자바에서 지원하는 다양한 기능 중 얼마전에 알게된 기능이 바로 SoftReference 클래스입니다. 이전에 번역했던 포스트에서 해당 클래스를 사용하면 손쉽게 Object Cache 를 구축할 수 있다고 설명되어있어서 한 번 살펴보게되었습니다. 와... 굉장히 편리한 녀석이더군요. (감동 또 감동) 이미 자바에 익숙하신 분들은 다들 알고 계신 내용일거 같은데, 개인적으로 실제 어플리케이션 개발을 할 때 유용하게 써먹은 만큼 안드로이드에서 SoftReference 를 이용하여 Object Cahce 를 활용하는 방법에 관하여 정리차원에서 간단하게 포스팅 해봅니다.


Reference 와 SoftReference


 SoftReference 는 일반적으로 자바에서 사용되는 Reference 보다 좀 더 부드러운 Reference 라고 할 수 있습니다. 일반 Reference 가 쇠사슬이라고 한다면 SoftReference 는 T.O.P 아니 고무줄이라고 할까요? 자바 어플리케이션은 수 많은 객체들로 이루어져 있습니다. 그리고 각각의 객체들은 JVM(Java Virtual Machine) 이 설정한 힙메모리 영역에 위치하게 되지요. (아마도?)  우리는 해당 객체를 참조할 수 있는 Reference 를 이용하여 여러가지 일들을 수행합니다. 만일 특정 객체가 아무런 참조도 같고 있지않다면 이는 더이상 사용될 수 없는 쓰레기(Garbage)에 불과한 셈이지요. 그리고 GC(Garbage Collector)는 아무런 참조를 갖고 있지 않은 이런 객체들을 제거하는 일을 수행합니다.


reference.jpg?type=w3
 <일반 Reference 가 쇠사슬이라면 SoftReference 는 힘주면 똑 하고 끊어지는 고무줄이라 할 수 있습니다.>
 

 SoftReference 는 힙 메모리 상의 특정 객체를 참조한다는 점에서 일반적은 Reference 와 거의 동일합니다만, 한가지 주요한 차이점이 있습니다. JVM 이 관리하는 메모리 공간이 부족할 경우, SoftReference 참조만 갖고 있는 객체는 GC 의 수거 대상이 될 수 있습니다. 보다 정확하게 JDK 에 기술된 내용을 살펴보면 다음과 같습니다.


"All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError. - SoftReference 로만 참조 가능한 모든 객체들은 JVM 에서 OutOfMemoryError 을 스로우 하기전에 미리 메모리 상에서 제거 되도록 보장된다."


 즉 일반적으로, 정상적인 참조를 갖고 있는 객체의 수가 늘어나거나 해당 객체가 요구하는 메모리 공간이 너무 클 경우에는 아무리 GC 가 동작하더라도, 확보할 수 없는 메모리 공간이 없기 때문에, OutOfMemoryError 가 발생할 수 있습니다. 하지만 SoftReference 를 사용하면, 이런 경우 해당 참조로 유지되고 있던 객체는 미리 정리가 되기때문에 OutOfMemoryError 없이 어플리케이션이 동작할 수 있지요.


 바로 이러한 특성 때문에, SoftReference 는 Object Cache 를 구현하는데 널리 사용됩니다. 일반적으로 Cache 는 어플리케이션 속도 향상을 위하여, 생성하 혹은 결과 값을 계산하는데 오랜 시간이 걸리는 결과물들을 메모리 혹은 파일등에 미리 저장해 두고, 해당 값이 필요한 경우 새롭게 구하는 대신 이미 저장된 값을 사용하는 방식입니다. 어플리케이션 개발자 입장에서는 어느 정도의 공간을 Cache 를 위한 공간으로 확보해 두느냐의 딜레마에 마주치게 되지요. 하지만 SoftReference 를 이용해서 Cache 를 구현하면, 메모리 공간을 어느 정도 잡아야하는지 고민할 필요 없이 그냥 아주 아주 큰 공간의 여유 메모리가 있다고 가정하면 됩니다. 어차피 메모리가 부족한 상황에서는 알아서 GC 가 해당 Cache 된 객체될을 메모리 상에서 제거해 줄테니 말입니다.


SoftReference 와 HashTable 을 이용한 Cache 구현


 SoftReference 의 기능이 매우 강력하기 때문에, 이를 이용하여 Cache 를 구현하는 것은 이외로 간단합니다. 


public class DrawableCache extends HashMap<Integer, SoftReference<Drawable>>{ Bitmap cacheImage = BitmapFactory.decodeResource(getResources(), R.drawable.noimage); public SoftReference<Drawable> get(Integer key) { String id = key.toString(); if(super.get(id) == null || super.get(id).get() == null){ //cache is empty. create a thumbnail image. Bitmap bitmap; if((Integer)key > 0){ bitmap = MediaStore.Images.Thumbnails.getThumbnail( getContentResolver(), (Integer)key, MediaStore.Images.Thumbnails.MICRO_KIND, null); } else{ //fail to create a thumbnail. so, just use a default image. bitmap = cacheImage; } if(bitmap != null){ put(id, new SoftReference<Drawable>(new BitmapDrawable(bitmap))); } } return super.get(id); } }

    

 코드는 짤막합니다. Integer 를 키 값으로 하고 Drawable 의 SoftReference 를 Value 값으로 하는 HashTable 을 하나 생성한 후, 해당 HashTable 에서 특정한 Object 를 꺼내려고 하는 경우, 해당 Object 가 이미 Cahce 되어 있는 경우는 그 Object 를 바로 반환하고 (속도가 향상되겠지요.) 그렇지 않은 경우에만 새롭게 이미지 썸네일을 생성하도록 구현되었습니다. 참조하고 있는 객체가 GC에 의해 이미 제거되어있는지 확인하기 위하여 SoftReference 의 값을 확인하고 있구요.


 위의 코드는 아주 간단하게 작성된 안드로이드 MediaStore 에 접근하여, 현재 폰에 존재하는 모든 이미지들을 로드해서 ListView 형식으로 화면상에 보여주는 어플리케이션을 구현하는데 사용되었습니다. 단순한 기능이지만, 일반적으로, MediaStore 에 저장된 이미지의 수가 많을 경우 별다른 조치를 취하지 않을 경우, OutOfMemoryError 가 발생하게 되거나, 매번 ListView 를 그릴때마다 새롭게 썸네일 이미지를 생성해야함으로 성능상에 문제가 발생하게 되지요. 


 하지만 위에 예에서 보인 것 처럼, SoftReference 를 이용하여 간단한 Cache 를 구성할 경우, 매번 View 가 그려질 때마다 이미지를 다시 그리지 않으면서도, 동시에 적절한 크기의 Cache 사이즈를 설정하고 관리하기 위해 머리 싸맬 필요없이 간단하게 원하는 효과를 얻을 수 있습니다. 


결론


  서두에 이야기했듯이 SoftReference 를 사용하는 것은 자바에 익숙한 개발자 분들에게는 아주 기초적인 내용일 것이라고 생각됩니다. 아직 자바에 익숙하지 않은 제 입장에서, SoftReference 클래스에대하여 잘 몰라 파일에 기반한 Cache 시스템을 만드려고 몇 시간 끙끙댄 아픈 기억이 있기에 이를 한번 정리하고, 혹시 비슷한 고생을 하고 계신 분들이 있지 않을까라는 생각에 포스팅 해 보았습니다.



출처 : http://blog.naver.com/PostView.nhn?blogId=huewu&logNo=110095553797