2017-02-07 4 views
0

Нужна помощь в эффективном управлении памятью для сценария ниже. Я извлекаю данные из двух разных баз данных и сравниваю данные на Java (в настоящее время тестирует одну базу данных с двумя запросами).Нужна помощь по набору результатов Java. Запуск из пространства кучи

Поскольку необходимо сравнить 9,8 миллионов записей, я копирую 50 тыс. Записей каждый раз и загружаю их в ArrayList и сравнивая с использованием Binarysearch. Хотя я очищаю (присваивая нулевому и запущенному gc) arraylist после каждой итерации, я получаю ошибку пространства кучи (Assigned 1GB RAM) после сравнения 2,5 миллиона записей.

Где утечка памяти в моем запросе?

Query1= select empno,ename from table1 order by empno; 
Query2= select empno,ename from table2 order by empno; 

ResultSet rs1 = st1.executeQuery(query1); 
ResultSet rs2 = st2.executeQuery(query2);    
for (;;) { 
    ArrayList<String> al = new ArrayList<String>(); 
    ArrayList<String> al1 = new ArrayList<String>(); 

    if (totalRecords1 == Ubound) 
     break; 

    Lbound = Ubound + 1; 
    Ubound = min(Ubound + 50000, totalRecords1); 
    System.out.println("Lbound : " + Lbound); 
    System.out.println("Ubound : " + Ubound); 

    for (int i = Lbound; i <= Ubound; i++) { 
     recordConcat1 = ""; recordConcat2 = ""; 
     String recordConcat1 = "", recordConcat2 = ""; 
     rs1.next(); 
     rs2.next(); 

     recordConcat1 = recordConcat1 + rs1.getString(z) + " ǀ "; 
     recordConcat2 = recordConcat2 + rs2.getString(z) + " ǀ "; 

     al.add(recordConcat1); 

     al1.add(recordConcat2); 

    } /* End of First Lap */ 

    System.out.println("End of Lap : "+lap++); 

    int index =0; 
    for(int like=0;like<al.size();like++) { 

     if(Collections.binarySearch(al1,al.get(like))>=0) 
      continue; 
     else { 
      System.out.println("Not matched : "+ al.get(like)); 
      break; 
     } 
    } 

    al =null; 
    al1=null; 
    System.gc(); 

} /* End of Infinite Loop */ 
+0

Какую базу данных + драйвер JDBC вы используете? –

+1

Почему вы не создаете представление в одной базе данных и не выбираете его из другой базы данных с помощью инструкции 'join' и не оставляете« тяжелую работу »в базе данных, которая знает, как управлять миллиардами записей, а не делать это на Java? –

+0

Первый вызов System.gc() просто подсказывает VM, что сбор мусора должен запускаться. С этой целью вы можете создать 2 ArrayList вне цикла for и очистить их. – xyclops

ответ

0

Вместо того, чтобы устанавливать ArrayLists на нуль и вызов GC. Вызовите ArrayList.clear() Это не освободит память ArrayLists, но повторно использует его. Более того, поскольку у вас есть фиксированная верхняя граница в 50000, передайте это число конструктору ArrayList, чтобы избежать перераспределения динамической памяти, при этом автоматически увеличивая ArrayLists с их начального размера по умолчанию 10.

С другой стороны, если я правильно прочитал , то, что вы пытаетесь достичь, - это определить, является ли каждый элемент одной таблицы другой. Поскольку данные сортируются, вы можете сделать это, не загружая куски в память, но одновременно просматривая оба ResultSets.

Я думаю, что ваш алгоритм не будет работать должным образом даже без ошибки в памяти. Вы читаете 50K из таблицы A и 50K из таблицы B. Теперь найдите каждый элемент куска B на куске A. Но что, если элемент в пределах первого 50000 из B находится в позиции 50001 A. Вы подумаете, что его нет, но на самом деле это. Правильно?

+0

Я согласен с тем, что если какая-либо запись не существует в обеих таблицах, сравнение может пойти не так. Я обработал такие сценарии вне кода, созданного здесь. Я сначала попытался использовать arraylist.clear(). Это не сработало. После некоторого анализа я указал массивы на нуль и провел GC. Я также попытался сравнить прямое повторение обоих результатов, но чтобы избежать такого подхода из-за производительности.Нынешний подход к поиску бинарного поиска кажется очень быстрым. –

+0

Я не вижу, почему параллельная итерация должна быть медленнее, чем предварительная загрузка + двоичный поиск. Если ваша база данных и JDBC-диск поддерживают ее, используйте setFetchSize для извлечения большого количества строк в каждом раунде. Это даст вам большой прирост производительности, если функция доступна. Кроме того, повторно используя ArrayLists, вы можете повторно использовать recordConcat1 и recordConcat2, преобразовывая их в объекты StringBuilder и очищая их на каждой iiteration. –

Смежные вопросы