안드로이드(Android) 앱에서 메모리 캐시 사이즈를 디바이스별로 동적으로 조절하기

안드로이드(Android)에서 많은 썸네일(Thumbnail)을 처리하기 위해서 많은 앱들이 1차 메모리, 2차 디스크 캐시를 사용하고 있다. 여기에서 2차 디스크는 용량이 충분하기 때문에 별 이슈가 없다. 하지만, 메모리 캐시의 경우에는 디바이스별로 다르기 때문에 보통은 작은 사이즈로 지정해서 사용하게 된다. 지금 출시되는 안드로이드 디바이스의 앱 메모리 설정을 보면, 이전보다 매우 크게 사용할 수 있는 것을 알수가 있다.

그래서, 메모리 캐시를 더 크게 사용해서, UX의 반응을 더 높이는 방법을 살펴보자. 기본적으로, http://www.sjava.net/332 를 보면,  안드로이드 OS의 설정정보를 읽어서, 디바이스의 정보를 알수가 있겠다.

앱마다 사용하는 썸네일 사이즈에 따라, 메모리를 점유하는 크기가 달라지기 때문에 이 내용은 앱에서 처리하는 썸네일의 크기에 따라 달라진다.

우선, 썸네일이 점유하는 메모리의 크기를 살펴보면..

100 x 100의 썸네일인 경우, 100x100x4의 크기이니 40,000 byte의 메모리를 점유한다고 보면 되겠다.  그래서, 대략적으로 캐시 사이즈에 따른 메모리 사용량을 가늠해 보면..

100×100 썸네일을 메모리에 100개 올리게 되면, 4M 정도의 메모리를 점유하게 될 것이고.. 이 정보를 기준으로 캐시 사이즈를 정하면 되겠다..

위의, 정보를 기준으로 해서 디바이스가 허용하는 앱의 힙 정보를 살펴보면..

* 갤럭시 넥서스

07-24 11:51:04.377: E/CacheUtil(27521): dalvik.vm.heapstartsize : 8m
07-24 11:51:04.377: E/CacheUtil(27521): dalvik.vm.heapgrowthlimit : 96m <– 최대 힙 사이즈를 기준으로 캐시의 사이즈를 조절한다.
07-24 11:51:04.377: E/CacheUtil(27521): dalvik.vm.heapsize : 256m <– 전체 힙 사이즈

* 넥서스 10

07-24 12:02:46.003: E/CacheUtil(12619): dalvik.vm.heapstartsize : 16m
07-24 12:02:46.008: E/CacheUtil(12619): dalvik.vm.heapgrowthlimit : 192m <– 최대 힙 사이즈를 기준으로 캐시의 사이즈를 조절한다.
07-24 12:02:46.008: E/CacheUtil(12619): dalvik.vm.heapsize : 512m <– 전체 힙 사이즈

위의 정보를 바탕으로 캐시클래스를 만들어 보면..

import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.graphics.Bitmap;

public class CacheUtil {
	static final String TAG = CacheUtil.class.getSimpleName();
	static int THUMBNAIL_CACHE_COUNT = 100;
	static boolean DEBUG = true;

	static{
		if(DEBUG) {
			Logger.e(TAG, "dalvik.vm.heapstartsize : "  + get("dalvik.vm.heapstartsize"));
			Logger.e(TAG, "dalvik.vm.heapgrowthlimit : "  + get("dalvik.vm.heapgrowthlimit"));
			Logger.e(TAG, "dalvik.vm.heapsize : "  + get("dalvik.vm.heapsize"));
			Logger.e(TAG, "cache_size : "  + getDynamicCacheSize());
		}
		
		THUMBNAIL_CACHE_COUNT = getDynamicCacheSize();
	}
		
	static LruCache<String, Bitmap> listCache = new LruCache<String, Bitmap>(THUMBNAIL_CACHE_COUNT);
	public static LruCache<String, Bitmap> listCache() {
		if(listCache == null)
			listCache = new LruCache<String, Bitmap>(THUMBNAIL_CACHE_COUNT);
		
		return listCache;
	}
	
	static LruCache<String, Bitmap> gridCache = new LruCache<String, Bitmap>(THUMBNAIL_CACHE_COUNT);
	public static LruCache<String, Bitmap> gridCache() {
		if(gridCache == null)
			gridCache = new LruCache<String, Bitmap>(THUMBNAIL_CACHE_COUNT);
		
		return gridCache;
	}

	
	static int getDynamicCacheSize() {
		String value = get("dalvik.vm.heapgrowthlimit");
		if(StringUtil.isEmpty(value))
			return THUMBNAIL_CACHE_COUNT;
		
		// M가 단위로 가져온다.. 
		int size = extractInt(value);
		if(size <= 64)
			return 100;
		
		if(size <= 128)
			return 200;
		
		return 300;
	}
	
	private static String get(String key) {
		try {
			Class clazz = Class.forName("android.os.SystemProperties");
			if (clazz == null)
				return "";

			Method method = clazz.getDeclaredMethod("get", String.class);
			if (method == null)
				return "";

			return (String) method.invoke(null, key);
		} catch (Exception e) {
			if (DEBUG)
				Logger.e(TAG, ExceptionUtil.exception(e));
		}

		return "";
	}
	
	private static int extractInt(String str) {
        Matcher matcher = Pattern.compile("\\d+").matcher(str);
        if (!matcher.find())
            throw new NumberFormatException("For input string [" + str + "]");

        return Integer.parseInt(matcher.group());
    }
}

위 클래스를 이용해서, 디바이스에 설정되어 있는 메모리 크기의 정보를 기준으로 메모리 캐시의 크기를 동적으로 설정할 수가 있겠다.

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.