Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > sax parser. файл 402 mgb. java heap space error


Автор: olegrolik 9.4.2009, 10:27
Не думал, что  возникнет такая ошибка, т.к. SAX парсер предназначается именно для больших потоков данных.
Как бы то ни было, вот код:
Код

package ru.ozonshop.tests;

import java.io.*;
import java.util.*;

import org.xml.sax.*;
import org.xml.sax.helpers.*;
import org.apache.xerces.parsers.SAXParser;

import ru.ozonshop.beans.*;

public class Flour extends DefaultHandler {
    private List<Offer> offers = new ArrayList<Offer>();
    private static List<Category> categories = new ArrayList<Category>();
    private static List<Category> parentCategories = new ArrayList<Category>();
    
    
    String currentTagName = "";
    float amount = 0;
    public void startDocument() {
        System.out.println("начало документа.");
    }
    public void endDocument() {
        System.out.println("конец документа."+offers.size());
    /*    Iterator it = offers.iterator();
        while(it.hasNext()) {
         
         Offer offer = (Offer)it.next();
         System.out.println("url="+offer.getUrl());
         System.out.println("price="+offer.getPrice());
         
         System.out.println("currencyId="+offer.getCurrencyID());
         System.out.println("categoryId=");
         List categId = offer.getCategoryID();
         System.out.println(categId.size());
         Iterator it2 = categId.iterator();
         while(it2.hasNext()) {
             String categ = (String)it2.next();
             System.out.print(categ+". ");
         }
         System.out.println("picture="+offer.getPicture());
         
         System.out.println("delivery="+offer.isDelivery());
         System.out.println("ordering="+offer.getOrdering());
         System.out.println("name="+offer.getName());
         System.out.println("vendor="+offer.getVendor());
         System.out.println("description="+offer.getDescription());
         System.out.println("--------------------------");
        }
        */
    }
    Offer offer = new Offer();
    public void characters(char ch[], int start, int length) {
    //    System.out.println(currentTagName);
    //    System.out.println("ch.length="+ch.length+", start="+start+", length="+length);
    //    String value = new String(ch, start, length);
//        System.out.print("VALUE==============="+value);
        
    //    System.out.println(". flag="+flag+", sFlag="+sFlag);
    /*    if(flag==1 && sFlag.equals("url")) {
            //    System.out.println("!");
            offer.setUrl(value);
            System.out.println("value for url="+value);
            offers.add(offer);
            
    }    */
        String value = new String(ch, start, length);
    //    System.out.println(value);
        if(sFlag.equals("url")) {
            offer.setUrl(new String(value));
        } else if(sFlag.equals("price")) {
            offer.setPrice(new String(value));
        } else if(sFlag.equals("currencyId")) {
            offer.setCurrencyID(new String(value));
        } else if(sFlag.equals("categoryId")) {
            categoryIDList.add(new String(value));
            //System.out.println("characters. size="+categoryIDList.size());
        }
        else if(sFlag.equals("picture")) {    
            offer.setPicture(new String(value));
    //        System.out.println("value for picture="+value);
    //        System.out.println(offer.getPicture());            
        } else if(sFlag.equals("delivery")) {
            offer.setDelivery(Boolean.getBoolean(new String(ch, start, length)));
        } else if(sFlag.equals("ordering")) {
            offer.setOrdering(new String(value));
        } else if(sFlag.equals("name")) {
            offer.setName(new String(value));
        } else if(sFlag.equals("vendor")) {
            offer.setVendor(new String(value));
        } else if(sFlag.equals("description")) {
            offer.setDescription(new String(value));
        }
            
    }
    
    int flag=0;
    int addFlag=0;
    String sFlag="";
    List categoryIDList = new ArrayList();
    public void startElement(String namespaceURI, String localName,
            String qName, Attributes attrs) {
        if(qName.equals("offer")&&flag==0) {
            //System.out.println("startElement->offer");
            flag=1;
            addFlag=0;
        }
        if (qName.equals("url")){
            sFlag = "url";
        }  else if(/*flag==1&&*/qName.equals("price")){
            sFlag = "price";
        } else if(qName.equals("currencyId")) {
            sFlag = "currencyId";
        } else if(qName.equals("categoryId")) {
            sFlag = "categoryId";
        } else if(/*flag==1&&*/qName.equals("picture")){
            sFlag = "picture";
        } else if(qName.equals("delivery")) {
            sFlag = "delivery";
        } else if(qName.equals("ordering")) {
            sFlag = "ordering";
        } else if(qName.equals("name")) {
            sFlag = "name";
        } else if(qName.equals("vendor")) {
            sFlag = "vendor";
        } else if(qName.equals("description")) {
            sFlag = "description";
        }
        
    //    currentTagName = qName;
    //    System.out.println(qName);
        
        /*
        if (localName.equals("category")) {
            Category category = new Category();
            String n = attrs.getValue("","parentId");
            if(n!=null) {
                System.out.println(qName);
                category.setId(qName);
                
            } else if(n==null) {
                
            }
       
        }
        */
    }
    public void endElement(String uri, String name, String qName) {
        if(qName.equals("offer")){
            flag=0;
            offer.setCategoryID(categoryIDList);
  //            System.out.println("endElement size="+categoryIDList.size());
            
  //            System.out.println("endElement size="+categoryIDList.size());
            
            offers.add(offer);
  //            System.out.println("offer.getCategoryID().size()="+offer.getCategoryID().size());
            
            offer=null; offer=new Offer();
        //    categoryIDList = null; categoryIDList = new ArrayList();
        }
        //offer.setPrice(null);
        //offer.setPicture(null);
        /*if(qName.equals("offer")) {
            System.out.println("!!!!!!!!!!!!!!!!!!!!!!");
            addFlag=1;
            flag=0;
        }
        
        sFlag="";
        */
        //flag=0;
    }

  public static void main(String[] args) {
    Flour f = new Flour();
    SAXParser p = new SAXParser();
    p.setContentHandler(f);
    try { p.parse(args[0]); } 
    catch (Exception e) {e.printStackTrace();}
  /*  System.out.println(offers.size());
    Iterator it = offers.iterator();
    while(it.hasNext()) {
     
     Offer offer = (Offer)it.next();
     System.out.println("url="+offer.getUrl());
     System.out.println("picture="+offer.getPicture());
     System.out.println("price="+offer.getPrice());
     System.out.println("--------------------------");
    }
    
    */
  }
}

Ошибка:
Код

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOfRange(Arrays.java:3209)
    at java.lang.String.<init>(String.java:216)
    at ru.ozonshop.tests.Flour.characters(Flour.java:67)
    at org.apache.xerces.parsers.AbstractSAXParser.characters(Unknown Source)
    at org.apache.xerces.impl.dtd.XMLDTDValidator.characters(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanContent(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
    at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
    at ru.ozonshop.tests.Flour.main(Flour.java:179)


xml-файл доступен по ссылке - http://www.ozon.ru/multimedia/yml/partner/div_book.xml


Может кто знает в чём дело?

Автор: Skynin 9.4.2009, 10:56
Увидевши:

Код

else if(qName.equals("categoryId"))
            sFlag = "categoryId";

10 раз

вместо
Код

            sFlag = qName;

и проверки в HashSet на допустимость qName

смотреть больше не хочется smile

Автор: olegrolik 9.4.2009, 11:01
Цитата(Skynin @ 9.4.2009,  10:56)


и проверки в HashSet на допустимость qName


Этот момент не понял.
А насчёт 10 раз - мой косяк.

Автор: ecologist 9.4.2009, 11:14
Можно посмотреть еще StAX - мне даже больше понравилось.

Автор: olegrolik 9.4.2009, 11:42
Цитата(ecologist @ 9.4.2009,  11:14)
Можно посмотреть еще StAX - мне даже больше понравилось.

StAx позволяет парсить потоки > 400 мегабайт?


Мне кажется, SAX тоже позволяет работать с большими потоками данных (почти уверен smile). Но где-то в коде я накосячил.


Только что попробовал разобрать файл в 42 мегабайта - успешно.

Автор: Skynin 9.4.2009, 11:54
Цитата

Только что попробовал разобрать файл в 42 мегабайта - успешно.

А сколько от первоначального объема остается в памяти в виде нужных данных в ArrayList - посчитали?

Если, скажем выбрасываются только xml теги, из 400Мб полезных данных 350, то 
1. нужно подкручивать параметры хипа JVM
2. использовать встроенную базу данных и копировать туда (Apache Derby, H2, ..., )

Автор: olegrolik 9.4.2009, 12:19
Цитата(Skynin @ 9.4.2009,  11:54)
Цитата

Только что попробовал разобрать файл в 42 мегабайта - успешно.

А сколько от первоначального объема остается в памяти в виде нужных данных в ArrayList - посчитали?

Если, скажем выбрасываются только xml теги, из 400Мб полезных данных 350, то 
1. нужно подкручивать параметры хипа JVM
2. использовать встроенную базу данных и копировать туда (Apache Derby, H2, ..., )

Парсил файл размером в 43 536 988 байт.
В коллекции насчитал 13 969 832 байта.

Думаю соотношение у файла в 400 мегов будет такое же.

Насчёт параметров JVM - я собираюсь поднимать приложение на хостинге, на самом дешёвом тарифе. Не думаю, что там можно увеличить память под мои нужды.

Автор: Skynin 9.4.2009, 12:37
Цитата

Насчёт параметров JVM - я собираюсь поднимать приложение на хостинге, на самом дешёвом тарифе. Не думаю, что там можно увеличить память под мои нужды.

Считаем - (13 969 832/43 536 988)*400 = 128,34909Мб

Выясняем - сколько по умолчанию дается.

Если нельзя увеличить - используем встраиваемую БД (или предоставляемую хостером, MySQL или какая у него доступна)

Автор: olegrolik 9.4.2009, 12:52
Резюме какое?
SAX читает любые потоки данных (звёздочка).
звёздочка - в зависимости от используемой памяти вашей JVM.  smile 
Получается ак? smile 

Автор: Skynin 9.4.2009, 13:00
Цитата

Получается ак?

Любой программе нужна память.

Если ее недостаточно в комьютере для реализации алгоритма, то:
либо нужно докупить
либо менять алгоритм

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

Причем тут SAX?
Если он, не может докупить памяти, не может увеличить квоту JVM?

Резюме:
Вам нужно либо учиться на программиста, либо бросать это дело,
потому что в данном конкретном случае выделяете в алгоритме памяти  128,34909Мб лично ВЫ, лично Ваш алгоритм, а никакой не SAX или что угодно.

То есть можно взять файл, размером 1 байт, и 134217728 раз добавить в ArrayList это байт и получить OutOfMemory и сделать вывод что функции чтения файла работают неправильно.

Цитата

Получается ак?

Автор: olegrolik 13.4.2009, 17:44
Возникла новая проблема. SAX пропускает символы. Некорректно распознаёт тэг categoryId.
например у товара с offerId=4295594, categoryId=109 вместо 1099413

Код

<offer id="4295594" available="true">
        <url>http://url</url>
        <price>1259</price>
        <currencyId>RUR</currencyId>
        <categoryId>1101405</categoryId>
        <categoryId>1099413</categoryId>
        <categoryId>1098339</categoryId>
        <picture>http://picture</picture>
        <delivery>true</delivery>
        <orderingTime>
          <ordering>На складе</ordering>
        </orderingTime>
        <name>имя </name>
        <vendor>Vendor</vendor>
        <description>ваваываываыв</description>
      </offer>



Что здесь может быть?

Автор: LSD 13.4.2009, 17:51
Цитата(olegrolik @  13.4.2009,  17:44 Найти цитируемый пост)
Что здесь может быть? 

Неправильное использование метода characters(). Этот метод не обязан сразу передавать все данные которые идут внутри тега, он может это следовать несколько последовательных вызовов.

Автор: olegrolik 14.4.2009, 10:23
Цитата(LSD @ 13.4.2009,  17:51)
Неправильное использование метода characters(). Этот метод не обязан сразу передавать все данные которые идут внутри тега, он может это следовать несколько последовательных вызовов.

Правда чтоль? smile 

Если серьёзно, то и так понятно, что проблема в этом методе.
Вчера в инете нашёл ответ на мой вопрос
вот он: http://www.coderanch.com/t/432967/XML-Related-Technologies/Missing-characters-with-SAX-Parser
Надо использовать вместо 
Код

String s = ""; // должно быть объявлено в классе
public void characters(char c[], int start, int length) {
  s = new String(ch, start,length);
}


Код

StringBuffer sb = new StringBuffer(); // должно быть объявлено в классе
public void characters(char c[], int start, int length) {
  sb = sb.append(new String(ch, start,length));
}



Как-то так.
Короче помогло.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)