#android #bitmap #virtual-machine #heap-memory
#Android #bitmap #виртуальная машина #куча-память
Вопрос:
После некоторого тестирования с готовым продуктом я только что обнаружил, что все аппаратные устройства, которые у меня есть, имеют большие кучи виртуальных машин.
Самый низкий — 32 МБ.
Мое приложение — это приложение с большим объемом памяти, которое загружает множество высококачественных альфа-изображений и выводит их на холст в виде анимации. Таких наборов может быть загружено до двух (один для текущей анимации и один для следующей)
Теперь, после уменьшения размера кучи виртуальной машины на одном из моих устройств до 16 МБ, я обеспокоен тем, что она фактически не будет запускаться на устройствах с таким маленьким размером кучи.
Поскольку я мало что могу сделать с размером изображений и мало что могу сделать для уменьшения количества изображений, я спрашиваю, как бы мне добиться того же результата с менее жесткими ограничениями памяти?
Спасибо
Ответ №1:
Когда вы говорите «высокое качество», вы имеете в виду высокое разрешение? Я предлагаю хранить в памяти только то, что вам нужно для отображения на экране, а остальное хранить в файловой системе. Затем вы могли бы обрабатывать его фрагментами в фоновом режиме. Не уверен, что это сработает для вас, я действительно не понимаю, что делает ваше приложение.
Комментарии:
1. Ну, под высоким качеством я подразумеваю, что все изображения загружены и отображаются как ARGB_8888, предложение других респондентов о их масштабировании бесполезно, потому что все изображения создаются именно в том размере, который им требуется для отображения на экране. По сути, приложение создает небольшие анимации изображений. Представьте себе, что я создаю эпизоды southpark во время выполнения. Загружаются только изображения для текущей «сцены», и при переключении на следующую у меня есть изображения для текущей и следующей «сцены». Изображения по сути являются «частями» любого движущегося объекта в «сцене».
2. Принято на том основании, что решением здесь был не метод загрузки изображений, потому что в любом случае они все равно должны быть растрово декодированы, но вместо этого в памяти должны храниться только используемые в данный момент изображения.
Ответ №2:
Вы можете использовать этот метод для декодирования изображений. Это может сделать их намного легче. Помните, что изображения становятся растровыми, когда они отображаются, увеличивая потребление памяти.
public static Bitmap decode(byte[] imageByteArray, int width, int height) {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length,
o);
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < width || height_tmp / 2 < height)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
o2.inTempStorage = new byte[Math.max(16 * 1024, width * height * 4)];
return BitmapFactory.decodeByteArray(imageByteArray, 0,
imageByteArray.length, o2);
// return BitmapFactory.decodeByteArray(imageByteArray, 0,
// imageByteArray.length);
}
где
width — МАКСИМАЛЬНАЯ ширина в пикселях, которую может иметь ImageView. height — МАКСИМАЛЬНАЯ высота в пикселях, которую может иметь ImageView.
Таким образом, растровое изображение станет легче, а приложение может потреблять меньше памяти.
(ПРИМЕЧАНИЕ: я скопировал этот метод и немного изменил его, я не помню исходный вопрос, поэтому я не могу указать URL)
Я использую для упорядочивания изображений массивы байтов и декодирую их только непосредственно перед их показом.
Теперь, как говорит Джеймс Л., лучше всего хранить изображения в файловой системе и переносить в память только при необходимости, но если вы этого не сделаете (мой случай). вы можете загружать изображения с:
public static byte[] getBytes(InputStream is) throws IOException {
int len;
int size = 1024;
byte[] buf;
if (is instanceof ByteArrayInputStream) {
size = is.available();
buf = new byte[size];
len = is.read(buf, 0, size);
} else {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
buf = new byte[size];
while ((len = is.read(buf, 0, size)) != -1)
bos.write(buf, 0, len);
buf = bos.toByteArray();
}
return buf;
}
public static byte[] downloadFileByteArray(String fileUrl)
throws IOException, MalformedURLException {
URL myFileUrl = null;
myFileUrl = new URL(fileUrl);
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
return getBytes(is);
}
Если у вас уже есть изображения в памяти, вы сможете превратить их в массивы байтов, используя методы, которые я представляю.
Кроме этого (и вызова System.gc()) вы мало что можете сделать (насколько я знаю). Возможно, продлить BMP в onPause() и onDestroy() и при необходимости перестроить их в onResume().
Комментарии:
1. У меня возникли проблемы с размером кучи виртуальной машины при загрузке «кучи высокого качества», точно так же, как @Hamid объясняет, что у него возникли. Я решил это, используя эти методы. Я начал хранить изображения в оперативной памяти в формате jpg fotmat вместо формата Drawable или Bitmap, что, конечно, если изображения не показывались в данный момент. Я сделал это, чтобы уменьшить потребление памяти. Это не совсем то, о чем он просит, но это может помочь решить его проблему. Теперь изменение метода декодирования в любом формате вместо массива байтов должно быть легко выполнено. Использование этого метода значительно снижает потребление памяти.
2. Конечно, это только ухудшает ситуацию? Мне нужно было бы не только иметь bytearray в памяти, но также, в момент отображения изображения, данные bitmap для него тоже. В моем стандартном варианте использования у меня отображаются почти, если не все изображения одновременно.
3. Когда я делал это, я не знал, что вы уже отображали только то, что было необходимо. Я только что прочитал комментарий, который вы дали к другому ответу, и в вашем случае, я думаю, лучше сохранять фотографии в файловой системе. Это хорошее решение, если вы одновременно показываете небольшое количество растровых изображений (и не хотите сохранять изображения на устройстве). Благодаря этому я смог создать полноэкранную галерею из 51 изображения в оперативной памяти, ничего не сохраняя на устройстве, с изображениями размером 100 кб.
4. Я просто подумал кое о чем, есть способ узнать VMHeap в Android, я плохо его помню, но друг однажды показал его мне. возможно, вы сможете проверить размер кучи и в зависимости от этого получить набор изображений более низкого качества, чтобы при необходимости снизить требования к куче. Это не лучший вариант, но он может позволить вам воспроизводить анимацию на устройствах с низким уровнем кучи виртуальной машины. Это лучшее, что я могу придумать. Если вам нужен метод для получения hep виртуальной машины, возможно, я смогу его найти, скажите мне, и я поищу его.