Как решить Недостаточно памяти, если ваша процедура возвращает большое количество записей
В настоящее время я работаю над приложением Java. Используемая база данных - Sybase ASE 15.0. В настоящее время я получаю следующую ошибку в одном из сценариев:
java.lang.OutOfMemoryError: Java heap space
У меня есть следующий вызов процедуры в моем коде:
CallableStatement cStmt = null;
ResultSet rs = null;
ArrayList list = new ArrayList();
Connection con = getConnection();
cStmt = con.prepareCall("call <proc-name>(?,?)", ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
boolean b;
// .....
// .....
while(rs.next()){
List dList = new ArrayList();
T t = new T();
t.setProp1(rs.getBoolean("isAvailable"));
t.setProp2(rs.getString("Name"));
t.setDList(dList);
....
....
t.setPropN(rs.getString("Property-name"));//many properties are read
// from db and POJO is populated.
b = true;
int Id = rs.getInt("Id");
do{
D d = new D();
d.setProp1(rs.getFloat("<property-name"));
....
....
d.setPropN(rs.getString("Property-name"));//many properties are read
dList.add(d);
if(rs.next()){
if(rs.getInt("Id")!=Id){
b = false;
rs.previous();
}
} else {
b = false;
rs.previous();
}
} while (b);
list.add(t);
}
Процедура получает диапазон дат в качестве аргументов. Если диапазон дат большой, он возвращает большое количество записей. Для небольшого количества записей он работает нормально, но для больших записей он дает исключение "недостаточно памяти". Я заметил, что если количество записей больше 11997, то это выдает эту ошибку.
Я прочитал, что простой набор результатов хранит записи в динамической памяти, но он должен работать с прокручиваемым набором результатов, верно?
Как мне удалить это исключение в этом случае.
3 ответа
Почему бы не использовать ограничения? Если вы не можете ограничить диапазон дат, который может привести к огромному набору данных, вы должны использовать ограничения, т.е. вы делаете что-то с первыми 100, затем со следующими 100 и т. Д. Тогда у вас есть только текущие 100 в памяти.
Сначала просто ресурс чистоты: пользуйся try (ResultSet rs = cStmt.query()) { ... }
чтобы закрыть набор результатов впоследствии.
Sвыдал результат хранимой процедуры во (временную) таблицу и использовал SELECT, возможно, разбитый на страницы. Затем набор результатов может повторяться. Вызов, вероятно, передает все данные в JDBC. Я не знаю возможностей хранимых процедур Sybase, но, возможно, вы можете там что-то делать.
Проверьте, используйте VARCHAR, а не CHAR или что-то подобное.
Используйте UTF-8, а не UTF-16LE.
При хранении в java, возможно, кэшируйте равные Strings/BigDecimals в карте идентичности, чтобы в данных использовался только первый экземпляр объекта.
Как насчет того, чтобы просто увеличить максимальную память кучи вашей виртуальной машины по умолчанию?
-Xmx<size> - to set the maximum Java heap size
-Xms<size> - to set the initial Java heap size
Вы также можете попробовать профилировщик, чтобы более точно определить утечку памяти. Вы должны быть осторожны с этим циклом while, с тем, что вы вставили в него, и с тем, что соответствует критериям GC
Проверьте эту информативную статью о стоимости создания объекта:
http://drmirror.net/2013/06/06/object-creation/
Хорошие методы эффективной работы с памятью для Java: https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf
Обновлено: в ответ на "Есть ли другой способ, что результирующий набор не считывает все записи в память одновременно и читает их порциями? " Попробуйте использовать setFetchSize для ResultSet (rs)
Узнайте больше о размере setFetch:
/questions/18654532/resultset-zagruzhaet-vse-dannyie-v-pamyat-ili-tolko-po-zaprosu/18654544#18654544
/questions/12475597/chto-i-kogda-mne-sleduet-ukazyivat-setfetchsize/12475610#12475610
/questions/8347460/putanitsa-s-metodom-setfetchsize-obekta-statement/8347472#8347472
Обновление 2 В ответ на ваш код цикла:
объявите все ваши переменные вне циклов и инициализируйте их, как вам нужно; Итак, перед циклом:
List dList;
T t;
int Id
D d;
while(rs.next()){
dList = new ArrayList();
t = new T();
// and so on...
list.add(t);
}
А потом попробуйте еще раз.