java - 堆内存已满并抛出 : java. lang.OutOfMemoryError: Java Heap Space

标签 java out-of-memory heap-memory

以下 servlet 代码每分钟都会收到巨大的 JSON 字符串,大约 2 小时后我总是收到 OutOfMemoryError: Java Heap Space

public class GetScanAlertServlet extends HttpServlet {

private String scanType = "";
private static final String path = "D:\\Mobile_scan_alerts8180";
private static final String stockFileName = "stock.txt";
private static final String foFileName = "fo.txt";
private static Logger logger = null;
private String currDate = "";
private DateFormat dateFormat;
private StringBuffer stockData;
private StringBuffer foData;
 StringBuffer data = new StringBuffer("");
// For average time of received data
private static float sum = 0;
private static float count = 0;
private static float s_sum = 0;
private static float s_count = 0;
private static float fo_sum = 0;
private static float fo_count = 0;

private static final File dir = new File(path);
private static final File stockFile = new File(path + "\\" + stockFileName);
private static final File foFile = new File(path + "\\" + foFileName);

public void init() {

    logger = MyLogger.getScanAlertLogger();

    if(logger == null) {
        MyLogger.createLog();
        logger = MyLogger.getScanAlertLogger();
    }

}

/**
 * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
 * methods.
 *
 * @param request servlet request
 * @param response servlet response
 * @throws ServletException if a servlet-specific error occurs
 * @throws IOException if an I/O error occurs
 */
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    PrintWriter out = response.getWriter();
    response.setContentType("text/plain");
    String strScan = "";

    try {

        String asof = null;

        scanType = request.getParameter("type");
        scanType = scanType == null ? "" : scanType;


        if(scanType.length() > 0){

            if(scanType.equalsIgnoreCase("s")) {
                stockData = null;
                stockData = new StringBuffer(request.getParameter("scanData"));
                stockData = stockData == null ? new StringBuffer("") : stockData;
            } else {
                foData = null;
                foData = new StringBuffer(request.getParameter("scanData"));
                foData = foData == null ? new StringBuffer("") : foData;
            }

        }

        asof = request.getParameter("asof");
        asof = asof == null ? "" : asof.trim();

        // Date format without seconds
        DateFormat formatWithoutSec = new SimpleDateFormat("yyyy/MM/dd HH:mm");

        dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date tmp = new Date();

        // format: yyyy/MM/dd HH:mm:ss
        currDate = dateFormat.format(tmp);

        //format: yyyy/MM/dd HH:mm
        Date asofDate = formatWithoutSec.parse(asof);
        Date cDate = formatWithoutSec.parse(currDate);
        cDate.setSeconds(0);


        System.out.println(asofDate.toString()+" || "+cDate.toString());

        int isDataExpired = asofDate.toString().compareTo(cDate.toString());

        if(isDataExpired > 0 || isDataExpired == 0) {

            if(scanType != null && scanType.length() > 0) {
                checkAndCreateDir();
                strScan = scanType.equalsIgnoreCase("s") ? "Stock Data Recieved at "+currDate
                        : "FO Data Recieved at "+currDate;
                //System.out.println(strScan);
            } else {
                strScan = "JSON of scan data not received properly at "+currDate;
                //System.out.println("GSAS: received null or empty");
            }

        } else {
            strScan = "GSAS: " + scanType + ": Received Expired Data of "+asofDate.toString()+" at "+cDate.toString();
            System.out.println(strScan);
        }
        scanType = null;


    } catch (Exception ex) {
        strScan = "Mobile server issue for receiving scan data";
        System.out.println("GSAS: Exception-1: "+ex);
        logger.error("GetScanAlertServlet: processRequest(): Exception: "+ex.toString());
    } finally {
        logger.info("GetScanAlertServlet: "+strScan);
        out.println(strScan);
    }

}

private void checkAndCreateDir() {

    try {
            boolean isStock = false;
            Date ddate = new Date();
            currDate = dateFormat.format(ddate);
            sum += ddate.getSeconds();
            count++;
            logger.info("Total Average Time: "+(sum/count));

            if(scanType.equalsIgnoreCase("s")){ //For Stock
                setStockData(stockData);

                Date date1 = new Date();
                currDate = dateFormat.format(date1);
                s_sum += date1.getSeconds();
                s_count++;
                logger.info("Stock Average Time: "+(s_sum/s_count));

                //file = new File(path + "\\" + stockFileName);
                isStock = true;

            } else if (scanType.equalsIgnoreCase("fo")) { //For FO
                setFOData(foData);

                Date date2 = new Date();
                currDate = dateFormat.format(date2);
                fo_sum += date2.getSeconds();
                fo_count++;
                logger.info("FO Average Time: "+(fo_sum/fo_count));

                //file = new File(path + "\\" +foFileName);
                isStock = false;
            }


            if(!dir.exists()) { // Directory not exists
                if(dir.mkdir()) {

                    if(isStock)
                        checkAndCreateFile(stockFile);
                    else
                        checkAndCreateFile(foFile);

                }
            } else { // Directory already exists

                    if(isStock)
                        checkAndCreateFile(stockFile);
                    else
                        checkAndCreateFile(foFile);
            }

    } catch (Exception e) {
        System.out.println("GSAS: Exception-2: "+e);
        logger.error("GetScanAlertServlet: checkAndCreateDir(): Exception: "+e);
    }

}

private void checkAndCreateFile(File file) {

    try{
        if(!file.exists()){ // File not exists

            if(file.createNewFile()){
                writeToFile(file);
            }

        } else { // File already exists
            writeToFile(file);
        }
    } catch (Exception e) {
        System.out.println("GSAS: Exception-3: "+e);
        logger.error("GetScanAlertServlet: checkAndCreateFile(): Exception: "+e.toString());
    }
}


private void writeToFile(File file) {

    FileOutputStream fop = null;

    try{

        if(scanType.equalsIgnoreCase("s")){ //For Stock
            data = getStockData();
        } else if (scanType.equalsIgnoreCase("fo")) { //For FO
            data = getFOData();
        }

        if(data != null && data.length() > 0 && file != null){

            fop = new FileOutputStream(file);

            byte[] contentBytes = data.toString().getBytes();
            for(byte b : contentBytes){
                fop.write(b);
            }
            //fop.write(contentBytes);

            fop.flush();


        } else {

            System.out.println("GSAS: Data is null/empty string");
            logger.info("GSAS: Data is null or empty string");

        }
        data = null;
    } catch (Exception  e) {
        System.out.println("GSAS: Exception-4: "+e);
        logger.info("GetScanAlertServlet: writeToFile(): Exception: "+e.toString());

    } finally {

        try {

            if(fop != null)
                fop.close();

        } catch (IOException ex) {
                java.util.logging.Logger.getLogger(GetScanAlertServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

private String readFromFile(String fileName){

    String fileContent = "";
    try{

        String temp = "";
        File file = new File(fileName);
        if(file.exists()){

            FileReader fr = new FileReader(file);
            BufferedReader br = new BufferedReader(fr);

            while((temp = br.readLine()) != null)
            {
                fileContent += temp;
            }
            br.close();
        } else {
            System.out.println("GSAS: File not exists to read");
            logger.info("GetScanAlertServlet: File not exists to read");
        }

        temp = null;
        file = null;

    } catch (Exception e) {
        System.out.println("GSAS: Exception-5: "+e);
        logger.error("GetScanAlertServlet: readFromFile(): Exception: "+e.toString());
    }
    return fileContent;
}

public StringBuffer getStockData() {

    //String temp="";
    //StringBuffer temp = (StringBuffer)scanDataSession.getAttribute("stock");
    //if(temp != null && temp.length() > 0) {
    //    return temp;
    //}
    if(stockData != null && stockData.length() > 0){
        return stockData;
    } else {
        stockData = null;
        stockData = new StringBuffer(readFromFile(path + "\\"+ stockFileName));
        return stockData;
    }
}


public StringBuffer getFOData(){

    //String temp="";
    //StringBuffer temp = (StringBuffer)scanDataSession.getAttribute("fo");
    //if(temp != null && temp.length() > 0) {
    //    return temp;
    //}
    if(foData != null && foData.length() > 0) {
        return foData; 
    } else {
        foData = null;
        foData = new StringBuffer(readFromFile(path + "\\" + foFileName));
        return foData;
    }   
}

}

当我重新启动 jboss 服务器时,每 2 小时后我总是会遇到以下异常,作为解决方案,我还增加了堆大小,但同样的问题仍然存在

ERROR [[GetScanAlertServlet]] Servlet.service() for servlet GetScan
AlertServlet threw exception
java.lang.OutOfMemoryError: Java heap space
        at sun.nio.cs.StreamEncoder.write(Unknown Source)
        at java.io.OutputStreamWriter.write(Unknown Source)
        at java.io.Writer.write(Unknown Source)
        at GetScanAlertServlet.writeToFile(GetScanAlertServlet.java:256)
        at GetScanAlertServlet.checkAndCreateFile(GetScanAlertServlet.java:236)
        at GetScanAlertServlet.checkAndCreateDir(GetScanAlertServlet.java:202)
        at GetScanAlertServlet.processRequest(GetScanAlertServlet.java:135)
        at GetScanAlertServlet.doPost(GetScanAlertServlet.java:377)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl
icationFilterChain.java:252)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF
ilterChain.java:173)
        at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFi
lter.java:81)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl
icationFilterChain.java:202)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF
ilterChain.java:173)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperV
alve.java:213)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextV
alve.java:178)
        at org.jboss.web.tomcat.security.CustomPrincipalValve.invoke(CustomPrinc
ipalValve.java:39)
        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(Securit
yAssociationValve.java:153)
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValv
e.java:59)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.j
ava:126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.j
ava:105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineVal
ve.java:107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.jav
a:148)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java
:856)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.proce
ssConnection(Http11Protocol.java:744)
        at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpo
int.java:527)
        at org.apache.tomcat.util.net.MasterSlaveWorkerThread.run(MasterSlaveWor
kerThread.java:112)
        at java.lang.Thread.run(Unknown Source)

最佳答案

虽然我没有立即看到问题,但您的代码无法正确处理资源分配/释放。这些问题不一定是由操作大型 JSON blob 引起的。

我刚刚观察到你没有释放你的资源(你打开文件,但没有在finally block 中关闭它们——有什么理由不这样做?),你可能会用StringBuilder来更好地进行字符串操作,或者只是使用某种现有的库(apache commons(io,string))可以为您完成此操作。

应该正确关闭计划的执行程序服务(也许使用容器提供的东西: Jboss thread pool )。

关于java - 堆内存已满并抛出 : java. lang.OutOfMemoryError: Java Heap Space,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36131221/

相关文章:

java - 编译模拟器的问题(java)

Java内存不足自动堆转储文件名

java - 由于内存不足错误,Openshift Wildfly 10 自动重新启动

java - 为什么我的 Java 堆转储只显示一半的堆?

java - 如何从 Avro Schema 获取所有字段名称?

java - 如何以任意顺序检查特定关键字/值对

java - 为什么 Vaadin 忽略第一个组件

c# - Graphics.DrawImage OutOFMemory 异常

java - J2ME中 "System.gc()"的作用是什么?

java - 在 Apache Karaf 下设置 Java 堆大小