Не могу победить java.lang.OutOfMemoryException: java heap space

165
06 июня 2019, 17:50

Помогите с советом, как победить java.lang.OutOfMemoryException: java heap space.

ОЗУ на ПК 8ГБ, и делал настройки -Xms7G, никак не проходить. Главное на МасBook при 8ГБ норм работает.

Суть такова, что загружаю с формы xlsx около 9000 строк, валится как раз на методе XSSFSheet.read. Если в этом файле оставить строк 5, то все ок.

сам метод загрузки создает объект каждой строки.

            rateClass = new RateClass(разные параметры, около 10 штук);
            if (!mapOfRates.containsValue(rateClass)) {
                mapOfRates.put(i, rateClass);
                i++;
            }
            rateClass = null;

Может кто-то сможешь подсказать, почему так(( На более мощной машине, где 16Гб озу и core i7 все нормально работает.

@Service
@Component
public class GetListOfRatesImpl implements GetList {
// Подключаем логгер
private static Logger logger = LoggerFactory.getLogger(GetListOfRatesImpl.class);
// Основаная мапа, куда записываем все маршруты
private Map<Integer, RateClass> mapOfRates = new HashMap<>();
// Переменные для работы с файлами
private File file;
private FileInputStream fileInputStream;
// Переменные для работы с Excel файлом(формат XLSX)
private XSSFWorkbook xssfWorkbook;
private XSSFSheet sheet;
RateClass rateClass = null;
private GetListOfRatesImpl() {
}
@Override
public void fillMap() {
    mapOfRates.clear();
    // Получаем файл формата xls
    try {
        fileInputStream = new FileInputStream(this.file);
        xssfWorkbook = new XSSFWorkbook(fileInputStream);
        // Заполняем Map данными
        sheet = xssfWorkbook.getSheetAt(0);
        int i = 0;
        for (int j = 1; j < sheet.getLastRowNum() + 1; j++) {
            XSSFRow row = sheet.getRow(0);
            String nameOfStationDeparture = null;
            String nameOfStationDestination = null;
            String customer = null;
            double rate = 0.00d;
            Date dateLoading = null;
            String nameCargo = null;
            String keyCargo = null;
            for (int c = 0; c < row.getLastCellNum(); c++) {
                if (row.getCell(c).getStringCellValue().trim().equals(JavaHelperBase.RATE_NAME_STATION_DEPARTURE)) {
                    XSSFRow xssfRow = sheet.getRow(j);
                    nameOfStationDeparture = xssfRow.getCell(c).getStringCellValue();
                }
                if (row.getCell(c).getStringCellValue().trim().equals(JavaHelperBase.RATE_NAME_STATION_DESTINATION)) {
                    XSSFRow xssfRow = sheet.getRow(j);
                    nameOfStationDestination = xssfRow.getCell(c).getStringCellValue();
                }
                if (row.getCell(c).getStringCellValue().trim().equals(JavaHelperBase.RATE_CUSTOMER)) {
                    XSSFRow xssfRow = sheet.getRow(j);
                    customer = xssfRow.getCell(c).getStringCellValue();
                }
                if (row.getCell(c).getStringCellValue().trim().equals(JavaHelperBase.RATE_NAME_CARGO)) {
                    XSSFRow xssfRow = sheet.getRow(j);
                    nameCargo = xssfRow.getCell(c).getStringCellValue();
                }
                if (row.getCell(c).getStringCellValue().trim().equals(JavaHelperBase.RATE_KEY_CARGO)) {
                    XSSFRow xssfRow = sheet.getRow(j);
                    if (xssfRow.getCell(c).getCellTypeEnum().equals(CellType.NUMERIC)) {
                        String val = Double.toString(xssfRow.getCell(c).getNumericCellValue());
                        double valueDouble = xssfRow.getCell(c).getNumericCellValue();
                        if ((valueDouble - (int) valueDouble) * 1000 == 0) {
                            val = (int) valueDouble + "";
                        }
                        keyCargo = val;
                    } else {
                        keyCargo = xssfRow.getCell(c).getStringCellValue();
                    }
                }
                if (row.getCell(c).getStringCellValue().trim().equals(JavaHelperBase.RATE_RATE)) {
                    XSSFRow xssfRow = sheet.getRow(j);
                    rate = xssfRow.getCell(c).getNumericCellValue();
                }
                if (row.getCell(c).getStringCellValue().trim().equals(JavaHelperBase.RATE_DATE_LOADING)) {
                    XSSFRow xssfRow = sheet.getRow(j);
                    dateLoading = xssfRow.getCell(c).getDateCellValue();
                    dateLoading.setHours(0);
                    dateLoading.setMinutes(0);
                    dateLoading.setSeconds(0);
                    if (dateLoading == null) dateLoading = new Date();
                }
            }
            rateClass = new RateClass(nameOfStationDeparture, nameOfStationDestination, customer, nameCargo, keyCargo, rate, dateLoading);
            if (!mapOfRates.containsValue(rateClass)) {
                mapOfRates.put(i, rateClass);
                i++;
            }
            rateClass = null;
        }
        logger.debug("Body rates: {}", mapOfRates);
    } catch (IOException e) {
        logger.error("Ошибка загруки файла - {}", e.getMessage());
    } catch (OLE2NotOfficeXmlFileException e1) {
        logger.error("Некорректный формат файла заявок, необходим формат xlsx");
    }
}
public Map<Integer, RateClass> getMapOfRates() {
    return mapOfRates;
}
public void setMapOfRates(Map<Integer, RateClass> mapOfRates) {
    this.mapOfRates = mapOfRates;
}
public void setFile(File file) {
    this.file = file;
    fillMap();
}
}

RateClass

public class RateClass implements Comparable<RateClass> {
// Подключаем логгер
private static Logger logger = LoggerFactory.getLogger(Route.class);
private String nameOfStationDeparture; // Станция отправления
private String nameOfStationDestination; // Станция назначения
private String customer; // Заказчик
private CargoClass cargo; // Груз
private double rate; // Ставка
private Date loadingDate; // Дата погрузки
public RateClass(String nameOfStationDeparture, String nameOfStationDestination, String customer, String nameCargo, String keyCargo, double rate, Date loadingDate) {
    this.nameOfStationDeparture = nameOfStationDeparture;
    this.nameOfStationDestination = nameOfStationDestination;
    this.customer = customer;
    this.cargo = new CargoClass(nameCargo, keyCargo);
    this.rate = rate;
    this.loadingDate = loadingDate;
}
public String getNameOfStationDeparture() {
    return nameOfStationDeparture;
}
public void setNameOfStationDeparture(String nameOfStationDeparture) {
    this.nameOfStationDeparture = nameOfStationDeparture;
}
public String getNameOfStationDestination() {
    return nameOfStationDestination;
}
public void setNameOfStationDestination(String nameOfStationDestination) {
    this.nameOfStationDestination = nameOfStationDestination;
}
public String getCustomer() {
    return customer;
}
public void setCustomer(String customer) {
    this.customer = customer;
}
public CargoClass getCargo() {
    return cargo;
}
public void setCargo(CargoClass cargo) {
    this.cargo = cargo;
}
public double getRate() {
    return rate;
}
public void setRate(double rate) {
    this.rate = rate;
}
public Date getLoadingDate() {
    return loadingDate;
}
public void setLoadingDate(Date loadingDate) {
    this.loadingDate = loadingDate;
}
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    RateClass rateClass = (RateClass) o;
    return Double.compare(rateClass.rate, rate) == 0 &&
            Objects.equals(nameOfStationDeparture, rateClass.nameOfStationDeparture) &&
            Objects.equals(nameOfStationDestination, rateClass.nameOfStationDestination) &&
            Objects.equals(customer, rateClass.customer) &&
            Objects.equals(cargo, rateClass.cargo) &&
            Objects.equals(loadingDate, rateClass.loadingDate);
}
@Override
public int hashCode() {
    return Objects.hash(nameOfStationDeparture, nameOfStationDestination, customer, cargo, rate, loadingDate);
}
@Override
public String toString() {
    return "RateClass{" +
            "nameOfStationDeparture='" + nameOfStationDeparture + '\'' +
            ", nameOfStationDestination='" + nameOfStationDestination + '\'' +
            ", customer='" + customer + '\'' +
            ", cargo=" + cargo +
            ", rate=" + rate +
            ", loadingDate=" + loadingDate +
            '}';
}
@Override
public int compareTo(RateClass o) {
    return o.loadingDate.compareTo(this.loadingDate);
}
}

Стек ошибки

java.lang.OutOfMemoryError: Java heap space
com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl.createChunk(Unknown Source)
com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl.ensureCapacity(Unknown Source)
com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl.createNode(Unknown Source)
com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl.createDeferredAttribute(Unknown Source)
com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl.setDeferredAttribute(Unknown Source)
com.sun.org.apache.xerces.internal.parsers.AbstractDOMParser.startElement(Unknown Source)
com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
org.apache.poi.util.DocumentHelper.readDocument(DocumentHelper.java:140)
org.apache.poi.POIXMLTypeLoader.parse(POIXMLTypeLoader.java:163)
org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument$Factory.parse(Unknown Source)
org.apache.poi.xssf.usermodel.XSSFSheet.read(XSSFSheet.java:226)
org.apache.poi.xssf.usermodel.XSSFSheet.onDocumentRead(XSSFSheet.java:218)
org.apache.poi.xssf.usermodel.XSSFWorkbook.parseSheet(XSSFWorkbook.java:443)
org.apache.poi.xssf.usermodel.XSSFWorkbook.onDocumentRead(XSSFWorkbook.java:408)
org.apache.poi.POIXMLDocument.load(POIXMLDocument.java:169)
org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:300)
com.uraltranscom.dynamicdistributionpark.service.impl.GetListOfRatesImpl.fillMap(GetListOfRatesImpl.java:72)
com.uraltranscom.dynamicdistributionpark.service.impl.GetListOfRatesImpl.setFile(GetListOfRatesImpl.java:158)
com.uraltranscom.dynamicdistributionpark.controller.Controller.routeList(Controller.java:51)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
Answer 1
  1. Не могу уловить зачем используется i, может быть достаточно списка вместо private Map<Integer, RateClass> mapOfRates = new HashMap<>(); или просто метод должен вернуть например: public List<RateClass> getRateClass() или public Set<RateClass> getRateClass() ?

  2. Можно считывать сразу файл XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file);

  3. Можно удалить все поля в сервисе они особо не нужны

  4. Кстати каждый getRow может создавать новый Integer если отличен от промежутка -128 - 127

    @Override
    public XSSFRow getRow(int rownum) {
        // Performance optimization: explicit boxing is slightly faster than auto-unboxing, though may use more memory
        final Integer rownumI = Integer.valueOf(rownum); // NOSONAR
        return _rows.get(rownumI);
    } 
    

Вынести в переменную XSSFRow xssfRow = sheet.getRow(j); выше цикла?

  1. Вынести все переменные тем самым избежать создания лишних объектов например:

    import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service;

    import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List;

    @Service public class GetListOfRatesImpl implements GetList {

    private static Logger logger = LoggerFactory.getLogger(GetListOfRatesImpl.class);
    @Override
    public List<RateClass> getRateClass(File file) {
        // Получаем файл формата xls
        List<RateClass> rateClasses = new ArrayList<>();
        try {
            XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file);
            XSSFSheet sheet = xssfWorkbook.getSheetAt(0);
            XSSFRow row = sheet.getRow(0);
            for (int j = 1; j < sheet.getLastRowNum() + 1; j++) {
                XSSFRow xssfRow = sheet.getRow(j);
                String nameOfStationDeparture = null;
                String nameOfStationDestination = null;
                String customer = null;
                double rate = 0.00d;
                Date dateLoading = null;
                String nameCargo = null;
                String keyCargo = null;
                for (int c = 0; c < row.getLastCellNum(); c++) {
                    String headerCell = row.getCell(c).getStringCellValue().trim();
                    XSSFCell cell = xssfRow.getCell(c);
                    if (headerCell.equals(JavaHelperBase.RATE_NAME_STATION_DEPARTURE)) {
                        nameOfStationDeparture = cell.getStringCellValue();
                    }
                    if (headerCell.equals(JavaHelperBase.RATE_NAME_STATION_DESTINATION)) {
                        nameOfStationDestination = cell.getStringCellValue();
                    }
                    if (headerCell.equals(JavaHelperBase.RATE_CUSTOMER)) {
                        customer = cell.getStringCellValue();
                    }
                    if (headerCell.equals(JavaHelperBase.RATE_NAME_CARGO)) {
                        nameCargo = cell.getStringCellValue();
                    }
                    if (headerCell.equals(JavaHelperBase.RATE_KEY_CARGO)) {
                        if (cell.getCellTypeEnum().equals(CellType.NUMERIC)) {
                            Double numericCellValue = cell.getNumericCellValue();
                            keyCargo = numericCellValue.intValue() + "";
                        } else {
                            keyCargo = cell.getStringCellValue();
                        }
                    }
                    if (headerCell.equals(JavaHelperBase.RATE_RATE)) {
                        rate = cell.getNumericCellValue();
                    }
                    if (headerCell.equals(JavaHelperBase.RATE_DATE_LOADING)) {
                        dateLoading = cell.getDateCellValue();
                        dateLoading.setHours(0);
                        dateLoading.setMinutes(0);
                        dateLoading.setSeconds(0);
                        if (dateLoading == null) dateLoading = new Date();
                    }
                }
                rateClasses.add(new RateClass(nameOfStationDeparture, nameOfStationDestination, customer, nameCargo, keyCargo, rate, dateLoading);)
            }
        } catch (IOException | InvalidFormatException e) {
            logger.error("Ошибка загруки файла - {}", e.getMessage());
        } catch (OLE2NotOfficeXmlFileException e1) {
            logger.error("Некорректный формат файла заявок, необходим формат xlsx");
        }
        logger.debug("Body rates: {}", rateClasses);
        return rateClasses;
    }
    

    }

  2. keyCargo как то сложно? два раза cell.getNumericCellValue()

        if (headerCell.equals(JavaHelperBase.RATE_KEY_CARGO)) {
                    if (cell.getCellTypeEnum().equals(CellType.NUMERIC)) {
                        Double numericCellValue = cell.getNumericCellValue();
                        keyCargo = numericCellValue.intValue() + "";
                    } else {
                        keyCargo = cell.getStringCellValue();
                    }
                }
    

Кстати если хип дамп есть то в нем должно быть понятно каких объектов много и на чем можно сэкономить

Answer 2

Причину нашел, оказалась проблема на машине, переустановил JVM и все заработало, спасибо всем.

READ ALSO
Как анимировать лейбл в pane c учетом размера окна программы?

Как анимировать лейбл в pane c учетом размера окна программы?

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

137
Перевод большого числа в byte

Перевод большого числа в byte

Делаю шифрование с помощью сдвигов битов в байтеНо если байту присвоить значение больше 127, оно начинает терять данные

134
Бинарные деревья и изоморфность

Бинарные деревья и изоморфность

Лучший источник в данном примере указано, что

159