(휴대폰 작성 및 소스코드가 모두 회사에 있는 관계로 디테일한 코드가 누락되니 양해바랍니다.)
여러 비트맵 이미지를 일반적인 문서 뷰어처럼 스크롤하며 볼 수 있게 만들어야 합니다.
현재, 스크롤 뷰어 안에 아이템스컨트롤을 배치하고 아이템스소스를 모델과 바인딩 한 후, 각각의 컨텐트 프레젠터를 이미지 컨트롤로 만들어 주었습니다.
모델에서는 BitmapImage 클래스를 멤버로 소유하고 있고, 사용자가 스크롤을 이동할 때마다 뷰포트 내부에 드러난 페이지의 이미지를 렌더링한 후, 나머지 페이지의 이미지는 모두 메모리에서 해제하려 합니다.
그러나 BitmapImage 클래스에서는 표준Dispose 패턴을 구현해주고 있지 않으므로 BitmapImage에 null을 대입한 후 BitmapImage가 참조중인 stream을 dispose 시키고 가비지컬렉터를 호출하는 방법을 사용하고 있습니다.
코드로 간략히 표현하면 다음과 같습니다.
(예제임을 감안 부탁드리겠습니다.)
class PictureModel
{
public BitmapImage Source { get; set; }
…
}
class PictureService
{
private Dictionary _cacheManager; // 인코딩된 이미지 캐싱
private Dictionary<int, Stream> _pictureManager;
public BitmapImage Render(int page)
{
// 디코딩된 BitmapImage 생성
}
public void Release(int page)
{
// 딕셔너리에서 스트림 제거
}
}
class PictureViewModel
{
…
public OvservableCollection Models;
public void ViewportChanged()
{
// Models를 순회하며 현재 뷰포트 영역에 보이지 않는 리소스 탐지
// Models.Source = null 대입
// GC.Collect() 호출
// 뷰포트에 가시화된 영역은 BitmapImage 생성
}
}
이 방식으로도 그럭저럭 동작은 하고 있습니다만, 아무래도 불만족스러운 것입니다. 우선 강제로 가비지 컬렉터를 동작시켜야 하는 부분이 부담스럽고, 스크롤을 매우 빠르게 움직일 경우에 (뷰포트에 나타나야하는 이미지도 순간적으로 늘어남으로) 메모리를 매우 많이 점유하게 됩니다. 물론 가비지 컬렉터에 요청을 보내놓기 때문에 곧 가비지가 회수되기는 합니다만, 만족할만큼 안정적이지는 않습니다.
이미지 컨트롤의 소스에 바인딩이 가능한 BitmapImage에서는 별도의 메모리 관리 기능을 제공하고 있는 것 같지 않은데, 혹시 wpf에서 비트맵 리소스들을 확실히 관리할 수 있는 더 나은 대안이 있을까요?