Android, беспокойство по поводу размера кучи виртуальной машины

#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 виртуальной машины, возможно, я смогу его найти, скажите мне, и я поищу его.