LINUX.ORG.RU

Загрузка bitmap-а в другом потоке заканчивается(иногда, меньше половины случаев) OutOfMemoryError

 , ,


0

2

Раньше работало так: грузим все картинки - запускаем игру. Работало корректно. Но загрузка была около секунды. Пытаемся улучшить, добавляем загрузку картинок в другой поток, а до того времени пишем на экране «Load...». Чаще чем 50% случаев работает все как надо. Но иногда падает с разными ошибками Например

E/SurfaceHolder﹕ Exception locking surface
    java.lang.IllegalArgumentException.
Но в данном случае интересует таки OutOfMemory.

public Bitmap scaleToWidth(Bitmap b , int width){
        return Bitmap.createScaledBitmap(b , width, width*b.getHeight()/b.getWidth() , true);
    }

    public Bitmap bitmapLoadRaw(int raw){
        return  BitmapFactory.decodeStream(getResources().openRawResource(raw)); // ЭТО ТА САМАЯ 81 СТРОЧКА ИЗ СООБЩЕНИЯ ОБ ОШИБКЕ НИЖЕ
    }
// много другого кода....
class WorkingClass implements Runnable{
                @Override
                public void run() {

                    fingerImg = scaleToWidth(bitmapLoadRaw(R.raw.finger),WHmin/5);
                    //много похожих запросов на загрузку других картинок, но падает именно на первой строчке
     }
}

WorkingClass workingClass = new WorkingClass();
            Thread thread = new Thread(workingClass);
            thread.start();

08-16 14:17:39.469  14270-14681/com.bacteria.app E/dalvikvm-heap﹕ Out of memory on a 2155624-byte allocation.
08-16 14:17:39.503  14270-14681/com.bacteria.app E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-1405
    java.lang.OutOfMemoryError
            at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:502)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:568)
            at com.bacteria.app.FullscreenActivity.bitmapLoadRaw(FullscreenActivity.java:81)
            at com.bacteria.app.FullscreenActivity$DrawView$1WorkingClass.run(FullscreenActivity.java:1257)
            at java.lang.Thread.run(Thread.java:856)

П.С. сам размер этой картинки весьма мал - 160 Кбайт. 700*800 пикс примерно.

★★★

Последнее исправление: ymn (всего исправлений: 1)

Я в отдельном потоке только подгружаю данные в память и декодирую их в формат, который понимает opengles. Далее выставляю флаг в главном потоке и главный поток загружает их в текстуру. В главном же потоке я отображаю прогресс-бар.

andreyu ★★★★★
()

Во-первых, есть asynctask для таких целей. Во-вторых, проверь сколько раз ты запускаешь поток. В-третьих, есть inDecodeSize или как там его, чтобы грузить уже нужного размера, а не ресайзить загруженное.

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

а не ресайзить загруженное.

У меня ресайз в большую сторону идет. Более того, без потока все работает - значит проблема именно в потоке.

Во-вторых, проверь сколько раз ты запускаешь поток.

Как это сделать? Я могу просто поставить Log.e("",«its must be only one»); внутри?

abs ★★★
() автор топика
Ответ на: комментарий от abs

Как это сделать? Я могу просто поставить Log.e("",«its must be only one»); внутри?

Можешь. Проще было бы посмотреть, что откуда вызывается, но для этого надо хорошо понимать как работает проект в целом. А чтобы быстрее, поставь лог :)

И да, ты картинку ресайклишь? Андроид не делает этого сам, тебе после завершения работы с картинкой надо ей делать recycle(). Например, той картинке, которая была загружена и отскалена (значит, исходная уже не нужна).

vurdalak ★★★★★
()
Ответ на: комментарий от abs

Роберт Мартин советует все критичные действия оборачивать в блоки try - catch - finally. Поставь в блок catch что-то типа println(exc.getMessage()), может быть, поможет.

LongLiveUbuntu ★★★★★
()
Ответ на: комментарий от vurdalak

И да, ты картинку ресайклишь?

Нет, не подскажешь как это сделать.

    public Bitmap scaleToWidth(Bitmap b , int width){
        return Bitmap.createScaledBitmap(b , width, width*b.getHeight()/b.getWidth() , true);
        // если я правильно понял я не могу ничего делать после return, а именно тут должно быть b.recacle();
    }

    public Bitmap bitmapLoadRaw(int raw){
        return  BitmapFactory.decodeStream(getResources().openRawResource(raw));// error here
    }
abs ★★★
() автор топика
Ответ на: комментарий от vurdalak

Не помогло

08-16 19:00:16.046  17540-17695/com.bacteria.app E/﹕ its must be only one, thred
08-16 19:00:16.178  17540-17695/com.bacteria.app E/dalvikvm-heap﹕ Out of memory on a 2155624-byte allocation.
08-16 19:00:16.230  17540-17695/com.bacteria.app E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-1638
    java.lang.OutOfMemoryError
            at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:502)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:568)
            at com.bacteria.app.FullscreenActivity.bitmapLoadRaw(FullscreenActivity.java:84)
            at com.bacteria.app.FullscreenActivity$DrawView$1WorkingClass.run(FullscreenActivity.java:1260)
            at java.lang.Thread.run(Thread.java:856)

abs ★★★
() автор топика
Ответ на: комментарий от abs

Картинки это больная тема у некоторых. Там куча проблем с оптимальным кэшированием, ресайзом, очищением памяти =)

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

Даже больше чем 9, там ещё цикл дальше. Небось никто из них вообще никогда не ресайклится.

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

Ты 9 картинок достаёшь и все держишь в памяти. Нафига? Нельзя по очереди это делать? Память не резиновая.

Стоп, а куда мне их??? Если все они могут рисоваться? примерно 5*3 картинок бактерий. И все они же должны быть в памяти

abs ★★★
() автор топика
Ответ на: комментарий от abs

И все они же должны быть в памяти

Доставать перед самой отрисовкой нельзя? Использовать LruCache и хранить ровно столько сколько влазит в память (а остальные подгружать по необходимости) нельзя?

vurdalak ★★★★★
()
Ответ на: комментарий от abs

b.recycle();

нужно вызывать там где ты создаешь картинку, за удаление/освобождение объектов должен отвечать владелец объекта, также лучше установить в null переменную.

art_corp
()

Я не знаю, что у тебя за проект и что ты там делаешь, но, возможно, стоит попробовать кешировать картинки. https://github.com/nostra13/Android-Universal-Image-Loader — кеширует на носителе и в памяти, довольно гибко настраивается.

Deleted
()
Ответ на: комментарий от vurdalak

Доставать перед самой отрисовкой нельзя?

У меня же игра, 60 кадров рисует в секунду. В теорию я могу уменьшит количество необходимых в какой-то конкретный момент в два раза. Но проблема НЕ В ЭТОМ. Я конечно не специалист, но оно работало на гораздо более слабом(а как следствие меньше памяти) телефоне. И на этом работало, пока я не закинул загрузку картинок через поток. Да что уж там, оно даже в этом случае работает больше 50%. Мне кажется я где-то наговнокодил лишнее.

abs ★★★
() автор топика
Ответ на: комментарий от abs

Но проблема НЕ В ЭТОМ.

Даже если сейчас проблема не в этом, там явно говнокод. Чтобы искать реальную проблему, надо сначала привести его в читабельный вид.

vurdalak ★★★★★
()
Ответ на: комментарий от vurdalak

там явно говнокод.

Я знаю, но я уже хочу это выпустить в продакшен. Работает оно отлично(если картинки грузить без потока) В любом случае, мне лучше вернуть все как было чем переписывать.

И да, эта ошибка срабатывает при загрузки самой первой картинки, и ошибка в самой загрузке(а не в увеличении размера где я забыл делать recycle();

abs ★★★
() автор топика
Ответ на: комментарий от vurdalak

там явно говнокод.

Я КЛИНИЧЕСКИЙ ИДИОТ!! Кажется проблема вообще в другом месте, у меня может быть выход сделан через жопу. В результате это падает не «иногда»,а каждый шестой запуск. Но вопрос все ещё оставляю открытым, вдруг я ошибся и проблема не в этом. Пойду искать способы решить эту проблему.

abs ★★★
() автор топика

08-16 14:17:39.503 14270-14681/com.bacteria.app E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-1405

Thread-1405

А что делают остальные 1400 потоков? Или в андройде ID потокам назначается не путем инкремента ID предыдущего запущенного потока?

nerh
()
Ответ на: комментарий от nerh

Именно так, но нумерация сквозная для всей системы.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.