@MikkiMouse

Есть ли утечка памяти?

Добрый день, ситуация такая:
Есть сервис, он скачивает изображения с сервера и сохраняет в кэш. Изображений примерно на 400Кб, но памяти отъедает раз в 10-15 больше. Подскажите, правильно ли я их скачиваю и сохраняю?

В коде сервиса скачиваю в методе downloadImages, получаю имена изображений, проверяю была ли картинка уже загружена, если нет, то скачиваю и сохраняю:
...
private boolean downloadImages() {
...
	String[] imageNames = data[0].split("\\s*" + Config.DATA_IMAGE_NAMES_SEP + "\\s*");
	for(String imgName : imageNames) {
		if(CacheManager.getInstance(this).getImage(imgName) == null) {
			Bitmap image = getBitmap(Config.SERVER_URL + imgName);

			CacheManager.getInstance(this).saveImage(imgName, image);
		}
	}
...
}

private Bitmap getBitmap(String aUrl) throws IOException {
	try {
		byte[] bitmapBytes = getUrlBytes(aUrl);
		return BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
	} catch (IOException ioe) {
		return null;
	}
}

private byte[] getUrlBytes(String aUrl) throws IOException {
	final HttpParams httpParams = new BasicHttpParams();
	HttpClient client = new DefaultHttpClient(httpParams);
	HttpGet request = new HttpGet(aUrl);
	request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0");
	request.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
	request.setHeader("Accept-Language", "ru,en-us;q=0.7,en;q=0.3");
	request.setHeader("Accept-Charset", "windows-1251,utf-8;q=0.7,*;q=0.7");

	HttpResponse response = client.execute(request);

	ByteArrayOutputStream out = new ByteArrayOutputStream();
	InputStream in = response.getEntity().getContent();
	int bytesRead = 0;
	byte[] buffer = new byte[1024];
	while ((bytesRead = in.read(buffer)) > 0) {
		out.write(buffer, 0, bytesRead);
	}
	out.close();

	return out.toByteArray();
}


Полученное изображение сохраняю в кэш в методе saveImage:
private CacheManager(Context context) {
	mContext = context;

	mLRU = new LruCache<Object, Object>(1024);
	loadImagesFromCacheToLRU();
}

public void saveImage(String aName, Bitmap aImage) {
	String filePath = mContext.getCacheDir().getAbsolutePath() + "/" + RESOURCE_IMAGES_PREFIX + aName;

	File file = new File(filePath);
	if(!file.exists()) {
		try {
			FileOutputStream fos = new FileOutputStream(filePath);
			aImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
			fos.flush();
			fos.close();
		} catch (IOException e) {
			Log.e(TAG, "Cannot save image to cache! " + e.getMessage());
		}
	}

	mLRU.put(aName, aImage);
}

public Bitmap getImage(String aName) {
	return (Bitmap) mLRU.get(aName);
}


Все ли верно в этих кусках кода?
  • Вопрос задан
  • 201 просмотр
Решения вопроса 1
@Tiberal
Проблема в цикле(и не одна)! Вы хараните слишком много битмапов в памяти!
Bitmap image = getBitmap(Config.SERVER_URL + imgName);

Каждый раз создает новый объект и держит его в памяти, и неизвестно когда эти объекты будут удалены сборщиком, вот вы и ловите OOM. Вам нужно доступаться с Bitmap посредством SoftReference. В этом случае, когда с памятью будет очень плохо gc освободит ресурсы обернутые в SoftReference.
Ну и не мешало бы дергать recycle() на Bitmap, когда она не нужна.
Config.SERVER_URL + imgName
Так тоже не стоит делать, стринги как и битмапы иммутабельны, и на каждой итерации будет создаваться новый объект. Юзайте стринг билдер.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
zagayevskiy
@zagayevskiy Куратор тега Android
Android developer at Yandex
Дались вам эти велосипеды. Используйте Picasso или Glide для загрузки изображений.
По поводу памяти - попробуйте попрофилировать приложение. А как вы поняли, что памяти съедает больше нужного?

По поводу lru cache - кажется, его вы юзаете неправильно. Он сам не будет правильно считать размер битмапа. В доках это нормально разобрано: developer.android.com/intl/ru/reference/android/ut...
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы