Кешировать или не кешировать?OutOfMemory

Интерфейс, диалоги, темы, стили, меню
Ответить
Артем Дегтев
Сообщения: 74
Зарегистрирован: 27 янв 2014, 00:05

Кешировать или не кешировать?OutOfMemory

Сообщение Артем Дегтев » 31 янв 2014, 13:45

Такая ситуация: есть БД, в ней хранятся текстовые данные и картинке в поле БЛОБ.
Есть список, в который выгружается база, потом при прокрутке, когда конец списка, в БД загружается еще 20 записей и они выводятся в список.
Но, если это повторить раз 20, то ошибка OutOfMemory.
Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?

Если из второго, то их наверное надо кешировать. Есть две функции для кеширования, поместить по ключу и достать по ключу. Как реализовать кеширование для изображение которые не отображаются на экране из списка, а когда фокус на них, дотавать их из Кеша.
Если кто то знает, помогите, очень нужно.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Кешировать или не кешировать?OutOfMemory

Сообщение rezak90 » 31 янв 2014, 14:16

Артем Дегтев писал(а):Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?
Не то ни другое (во втором вполне уверен, на счёт первого может кто то поправит). Наверное где то не закрываешь потоки, проследи за памятью.
P.S. никогда не понимал зачем в андроиде хранить картинки в бд.
R.id.team
Политика на форуме запрещена

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: Кешировать или не кешировать?OutOfMemory

Сообщение Foenix » 31 янв 2014, 14:27

про список не знаю, макс размер базы данных - около 2 гб.
Вот еще список ограничений, кому нужно
http://www.sqlite.org/limits.html
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

Аватара пользователя
anber
Сообщения: 584
Зарегистрирован: 10 июн 2013, 15:05
Откуда: UA

Re: Кешировать или не кешировать?OutOfMemory

Сообщение anber » 31 янв 2014, 14:44

http://www.youtube.com/watch?v=_CruQY55HOk

Upd. для кеша можно использовать LruCache

Upd2. покажи метод getView в адаптере ListView
Личные сообщения с просьбой ответить на форуме или написать программу я просто удаляю, если я в хорошем настроении. Если в плохом добавляю автора в черный список. По любым другим вопросам feel free to write to me.

Артем Дегтев
Сообщения: 74
Зарегистрирован: 27 янв 2014, 00:05

Re: Кешировать или не кешировать?OutOfMemory

Сообщение Артем Дегтев » 31 янв 2014, 15:13

anber писал(а):http://www.youtube.com/watch?v=_CruQY55HOk

Upd. для кеша можно использовать LruCache

Upd2. покажи метод getView в адаптере ListView
Именно так и думал кешировать, с помощью LruCache. Но пишут что не нужно.
Вот метод:

Код: Выделить всё

 public View getView(final int position, View convertView, ViewGroup parent) {
  ViewHolder holder = new ViewHolder();
  SearchResultItem rowItem = getItem(position);
  
  if(convertView == null){
   LayoutInflater mInflater = (LayoutInflater) context
     .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
   convertView = mInflater.inflate(R.layout.news, null);
   new ViewHolder();
   holder.SmallImageNews = (ImageView) convertView
     .findViewById(R.id.NewsImg);
   holder.NameNews = (TextView) convertView
     .findViewById(R.id.NameNews);
   holder.updateDate = (TextView) convertView
     .findViewById(R.id.updateDate);
;
      
   convertView.setTag(holder);
  } else
   holder = (ViewHolder) convertView.getTag();
  
        holder.NameNews.setText(rowItem.getName());
        holder.updateDate.setText(rowItem.getUpdateDate()t);
        holder.SmallImageNews.setImageDrawable(rowItem.getSmallImageNews());
   
        holder = null;

        return convertView;
 }

Артем Дегтев
Сообщения: 74
Зарегистрирован: 27 янв 2014, 00:05

Re: Кешировать или не кешировать?OutOfMemory

Сообщение Артем Дегтев » 31 янв 2014, 15:14

rezak90 писал(а):
Артем Дегтев писал(а):Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?
Не то ни другое (во втором вполне уверен, на счёт первого может кто то поправит). Наверное где то не закрываешь потоки, проследи за памятью.
P.S. никогда не понимал зачем в андроиде хранить картинки в бд.
Картинки храню в базе для того, что бы когда пользователь запустил приложение без доступа к интернету, картинки новостей, миниатюры, отображались на экране.

Артем Дегтев
Сообщения: 74
Зарегистрирован: 27 янв 2014, 00:05

Re: Кешировать или не кешировать?OutOfMemory

Сообщение Артем Дегтев » 31 янв 2014, 15:19

rezak90 писал(а):
Артем Дегтев писал(а):Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?
Не то ни другое (во втором вполне уверен, на счёт первого может кто то поправит). Наверное где то не закрываешь потоки, проследи за памятью.
P.S. никогда не понимал зачем в андроиде хранить картинки в бд.
В смысле последить за памятью? Как это сделать?

Аватара пользователя
anber
Сообщения: 584
Зарегистрирован: 10 июн 2013, 15:05
Откуда: UA

Re: Кешировать или не кешировать?OutOfMemory

Сообщение anber » 31 янв 2014, 15:30

Артем Дегтев писал(а):
rezak90 писал(а):
Артем Дегтев писал(а):Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?
Не то ни другое (во втором вполне уверен, на счёт первого может кто то поправит). Наверное где то не закрываешь потоки, проследи за памятью.
P.S. никогда не понимал зачем в андроиде хранить картинки в бд.
В смысле последить за памятью? Как это сделать?
я ссылку кидал на видео - http://www.youtube.com/watch?v=_CruQY55HOk

UPD. У меня было приложение где картинки хранились в БД, размер которой приблизительно 200Мб, и отображались в ListView, и приложение не падало с OOME, так что проблема где-то в логике.
Личные сообщения с просьбой ответить на форуме или написать программу я просто удаляю, если я в хорошем настроении. Если в плохом добавляю автора в черный список. По любым другим вопросам feel free to write to me.

Аватара пользователя
anber
Сообщения: 584
Зарегистрирован: 10 июн 2013, 15:05
Откуда: UA

Re: Кешировать или не кешировать?OutOfMemory

Сообщение anber » 31 янв 2014, 15:42

Собственно если влом разбираться с MAT можно заюзать следующий метод:

Код: Выделить всё

  public static void memoryUsegeLog(Context context, String tag) {
    logToFile("MyMemoryInfo", "=============================begin=============================");
    logToFile("MyMemoryInfo", "ActivityName: " + context.getClass().getSimpleName());
    logToFile("MyMemoryInfo", "TAG: " + tag);
    Runtime rt = Runtime.getRuntime();
    long maxMemory = rt.maxMemory();
    logToFile("MyMemoryInfo", "maxMemory:" + Long.toString(maxMemory / 1024) + "K");


    long freeMemory = rt.freeMemory();
    long totalMemory = rt.totalMemory();
    logToFile("MyMemoryInfo", "freeMemory:" + Long.toString(freeMemory / 1024) + "K");
    logToFile("MyMemoryInfo", "totalMemory:" + Long.toString((totalMemory) / 1024) + "K");
    logToFile("MyMemoryInfo", "usedMemory:" + Long.toString((totalMemory - freeMemory) / 1024) + "K");
    double frePers = (double) freeMemory / totalMemory * 100;
    logToFile("MyMemoryInfo", "freeMemoryPersent:" + Double.toString(frePers));

    logToFile("MyMemoryInfo", "NativeHeapAllocatedSize:" + Long.toString(Debug.getNativeHeapAllocatedSize() / 1024) + "K");
    logToFile("MyMemoryInfo", "NativeHeapFreeSize:" + Long.toString(Debug.getNativeHeapFreeSize() / 1024) + "K");
    logToFile("MyMemoryInfo", "NativeHeapSize:" + Long.toString(Debug.getNativeHeapSize() / 1024) + "K");

    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    int memoryClass = am.getMemoryClass();
    logToFile("MyMemoryInfo", "memoryClass:" + Integer.toString(memoryClass));

    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    am.getMemoryInfo(memoryInfo);
    logToFile("MyMemoryInfo", "availMem " + Long.toString(memoryInfo.availMem / 1024) + "K");
    logToFile("MyMemoryInfo", "lowMemory " + memoryInfo.lowMemory);
    logToFile("MyMemoryInfo", "threshold " + Long.toString(memoryInfo.threshold / 1024) + "K");

    logToFile("MyMemoryInfo", "==============================end==============================");
  }

  public static void logToFile(String tag, final String stringToFile) {
    File myFile = new File("/sdcard/mylog.txt");
    try {
      myFile.createNewFile();
      FileOutputStream fOut = new FileOutputStream(myFile, true);
      OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
      myOutWriter.append(stringToFile);
      myOutWriter.append("\r\n");
      myOutWriter.close();
      fOut.close();
    } catch (IOException e) {
      Log.e("MyMemoryInfo", e.toString());
    }
    Log.i(tag, stringToFile);
  }
В принципе удобно если приложение падает у клиента с OOME неизвестно почему - пишет в файл на сд карту, и в лог с тегом "MyMemoryInfo", потом у клиента можно просто попросить файлик mylog.txt.
Как использовать - напихать во всех подозрительных местах вызовы типа:
memoryUsegeLog(context, "begin getView method");
...
memoryUsegeLog(context, "end getView method");

и таким нехитрым способом найти место на котором тратится память.
Личные сообщения с просьбой ответить на форуме или написать программу я просто удаляю, если я в хорошем настроении. Если в плохом добавляю автора в черный список. По любым другим вопросам feel free to write to me.

Артем Дегтев
Сообщения: 74
Зарегистрирован: 27 янв 2014, 00:05

Re: Кешировать или не кешировать?OutOfMemory

Сообщение Артем Дегтев » 31 янв 2014, 17:53

anber писал(а):Собственно если влом разбираться с MAT можно заюзать следующий метод:

Код: Выделить всё

  public static void memoryUsegeLog(Context context, String tag) {
    logToFile("MyMemoryInfo", "=============================begin=============================");
    logToFile("MyMemoryInfo", "ActivityName: " + context.getClass().getSimpleName());
    logToFile("MyMemoryInfo", "TAG: " + tag);
    Runtime rt = Runtime.getRuntime();
    long maxMemory = rt.maxMemory();
    logToFile("MyMemoryInfo", "maxMemory:" + Long.toString(maxMemory / 1024) + "K");


    long freeMemory = rt.freeMemory();
    long totalMemory = rt.totalMemory();
    logToFile("MyMemoryInfo", "freeMemory:" + Long.toString(freeMemory / 1024) + "K");
    logToFile("MyMemoryInfo", "totalMemory:" + Long.toString((totalMemory) / 1024) + "K");
    logToFile("MyMemoryInfo", "usedMemory:" + Long.toString((totalMemory - freeMemory) / 1024) + "K");
    double frePers = (double) freeMemory / totalMemory * 100;
    logToFile("MyMemoryInfo", "freeMemoryPersent:" + Double.toString(frePers));

    logToFile("MyMemoryInfo", "NativeHeapAllocatedSize:" + Long.toString(Debug.getNativeHeapAllocatedSize() / 1024) + "K");
    logToFile("MyMemoryInfo", "NativeHeapFreeSize:" + Long.toString(Debug.getNativeHeapFreeSize() / 1024) + "K");
    logToFile("MyMemoryInfo", "NativeHeapSize:" + Long.toString(Debug.getNativeHeapSize() / 1024) + "K");

    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    int memoryClass = am.getMemoryClass();
    logToFile("MyMemoryInfo", "memoryClass:" + Integer.toString(memoryClass));

    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    am.getMemoryInfo(memoryInfo);
    logToFile("MyMemoryInfo", "availMem " + Long.toString(memoryInfo.availMem / 1024) + "K");
    logToFile("MyMemoryInfo", "lowMemory " + memoryInfo.lowMemory);
    logToFile("MyMemoryInfo", "threshold " + Long.toString(memoryInfo.threshold / 1024) + "K");

    logToFile("MyMemoryInfo", "==============================end==============================");
  }

  public static void logToFile(String tag, final String stringToFile) {
    File myFile = new File("/sdcard/mylog.txt");
    try {
      myFile.createNewFile();
      FileOutputStream fOut = new FileOutputStream(myFile, true);
      OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
      myOutWriter.append(stringToFile);
      myOutWriter.append("\r\n");
      myOutWriter.close();
      fOut.close();
    } catch (IOException e) {
      Log.e("MyMemoryInfo", e.toString());
    }
    Log.i(tag, stringToFile);
  }
В принципе удобно если приложение падает у клиента с OOME неизвестно почему - пишет в файл на сд карту, и в лог с тегом "MyMemoryInfo", потом у клиента можно просто попросить файлик mylog.txt.
Как использовать - напихать во всех подозрительных местах вызовы типа:
memoryUsegeLog(context, "begin getView method");
...
memoryUsegeLog(context, "end getView method");

и таким нехитрым способом найти место на котором тратится память.
Спасибо, нашел ошибку. Теперь пытаюсь решить.

Ответить