堆内存变满并抛出:java.lang.OutOfMemoryError:Java堆空间

时间:2016-03-21 12:36:17

标签: java out-of-memory heap 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)

2 个答案:

答案 0 :(得分:1)

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

我刚刚观察到你没有释放你的资源(你打开文件,但不要在finally块中关闭它们 - 任何理由不要?),你可能会更好地使用StringBuilder进行字符串操作或只是使用某种现有的库(apache commons(io,string))为你做。

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

答案 1 :(得分:0)

首先,我必须重写大部分代码。我知道这样做是不好的做法,我们在这里教导和帮助。其他人没有工作。但我真的能够阅读代码,并且难以理解。

以下是我发现的问题的要点

  • 没有finally条款,因此,如果发生异常,您的FileWriter,&#39; FileReader , and BufferedReader`从未关闭。
  • 尽可能不使用static,路径和文件名永远不会改变。此外,您的DateFormat从未更改,因此将其移至static
  • 当下一行从请求参数获取字符串时,不确定为什么要将字符串设置为null,如果它为null,则无论如何都将其更改为空字符串。
  • 不确定为什么要将日期转换为字符串来比较它们。日期具有可比性。

无论如何这里的代码是希望它有所帮助

public class GetScanAlertServlet extends HttpServlet
{
    private static final String PATH            = "D:\\Mobile_scan_alerts";
    private static final String STOCK_FILE_NAME = "stock.txt";
    private static final String FO_FILE_NAME    = "fo.txt";
    private static final String EMPTY           = "";

    private static final DateFormat FORMAT_WITHOUT_SEC = new SimpleDateFormat("yyyy/MM/dd HH:mm");

    // For average time of received data
    private static float SUM      = 0;
    private static float S_SUM    = 0;
    private static float FO_SUM   = 0;
    private static float COUNT    = 0;
    private static float S_COUNT  = 0;
    private static float FO_COUNT = 0;

    private static Logger LOGGER = null;

    private String scanType;
    private String stockData;
    private String foData;

    @Override
    public void init()
    {
        LOGGER = MyLogger.getScanAlertLogger();
        if (LOGGER == null)
        {
            MyLogger.createLog();
            LOGGER = MyLogger.getScanAlertLogger();
        }
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo()
    {
        return "Short description";
    }

    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request  servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException      if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request  servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException      if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        processRequest(request, response);
    }

    /**
     * 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 = EMPTY;

        try
        {
            scanType = getRequestParameter(request, "type");
            if (scanType.length() > 0)
            {
                if (scanType.equalsIgnoreCase("s"))
                {
                    stockData = getRequestParameter(request, "scanData");
                }
                else
                {
                    foData = getRequestParameter(request, "scanData");
                }
            }

            //format: yyyy/MM/dd HH:mm
            Date asofDate = FORMAT_WITHOUT_SEC.parse(getRequestParameter(request, "asof"));
            Date currDate = new Date();
            currDate.setSeconds(0);
            System.out.println(asofDate.toString() + " || " + currDate.toString());
            if (asofDate.compareTo(currDate) >= 0)
            {
                if (scanType != null && scanType.length() > 0)
                {
                    checkAndCreateDir();
                    strScan =
                            scanType.equalsIgnoreCase("s") ? "Stock Data Recieved at " + currDate :
                                    "FO Data Recieved at " + currDate;
                }
                else
                {
                    strScan = "JSON of scan data not received properly at " + currDate;
                }
            }
            else
            {
                strScan = "GSAS: " + scanType + ": Received Expired Data of " + asofDate.toString()
                        + " at " + currDate.toString();
                System.out.println(strScan);
            }
        }
        catch (Exception ex)
        {
            strScan = "Mobile server issue for receiving scan data";
            LOGGER.error("GetScanAlertServlet: processRequest(): Exception: " + ex.toString());
        }
        finally
        {
            LOGGER.info("GetScanAlertServlet: " + strScan);
            out.println(strScan);
            out.close();
        }
    }

    private void checkAndCreateDir()
    {
        try
        {
            File dir = new File(PATH);
            if (!dir.exists())
            {
                dir.mkdir();
            }
            File file = null;

            SUM += new Date().getSeconds();
            COUNT++;
            LOGGER.info("Total Average Time: " + (SUM / COUNT));

            if (scanType.equalsIgnoreCase("s"))
            { //For Stock
                S_SUM += new Date().getSeconds();
                S_COUNT++;
                LOGGER.info("Stock Average Time: " + (S_SUM / S_COUNT));

                file = new File(PATH + System.lineSeparator() + STOCK_FILE_NAME);
            }
            else if (scanType.equalsIgnoreCase("fo"))
            { //For FO
                FO_SUM += new Date().getSeconds();
                FO_COUNT++;
                LOGGER.info("FO Average Time: " + (FO_SUM / FO_COUNT));

                file = new File(PATH + System.lineSeparator() + FO_FILE_NAME);
            }
            checkAndCreateFile(file);
        }
        catch (Exception e)
        {
            //System.out.println("GSAS: Exception-2: "+e);
            LOGGER.error("GetScanAlertServlet: checkAndCreateDir(): Exception: " + e.toString());
        }
    }

    private void checkAndCreateFile(File file)
    {
        try
        {
            if(!file.exists())
            {
                file.createNewFile();
            }
            writeToFile(file);
        }
        catch (Exception e)
        {
            LOGGER.error("GetScanAlertServlet: checkAndCreateFile(): Exception: " + e.toString());
        }
    }

    private void writeToFile(File file) throws IOException
    {
        String data = EMPTY;
        if (scanType.equalsIgnoreCase("s"))
        { //For Stock
            if (stockData == null)
            {
                stockData = readFromFile(PATH + System.lineSeparator() + STOCK_FILE_NAME);
            }
            data = stockData;
        }
        else if (scanType.equalsIgnoreCase("fo"))
        { //For FO
            if (foData == null)
            {
                foData = readFromFile(PATH + System.lineSeparator() + FO_FILE_NAME);
            }
            data = foData;
        }
        FileWriter fileWriter = null;
        try
        {
            if (data != null && data.length() > 0)
            {
                fileWriter  = new FileWriter(file);
                fileWriter.write(data.toString());
            }
            else
            {
                System.out.println("GSAS: Data is null/empty string");
                LOGGER.info("GSAS: Data is null or empty string");
            }
        }
        catch (Exception e)
        {
            LOGGER.info("GetScanAlertServlet: writeToFile(): Exception: " + e.toString());
        }
        finally
        {
            if (fileWriter != null)
            {
                fileWriter.flush();
                fileWriter.close();
            }
        }
    }

    private String readFromFile(String fileName) throws IOException
    {
        String fileContent = EMPTY;
        FileReader fr = null;
        BufferedReader br = null;
        try
        {
            File file = new File(fileName);
            if (file.exists())
            {
                fr = new FileReader(file);
                br = new BufferedReader(fr);

                String temp;
                while ((temp = br.readLine()) != null)
                {
                    fileContent += temp;
                }
            }
            else
            {
                System.out.println("GSAS: File not exists to read");
                LOGGER.info("GetScanAlertServlet: File not exists to read");
            }
        }
        catch (Exception e)
        {
            LOGGER.error("GetScanAlertServlet: readFromFile(): Exception: " + e.toString());
        }
        finally
        {
            if (fr != null)
            {
                fr.close();
            }
            if (br != null)
            {
                br.close();
            }
        }
        return fileContent;
    }

    private String getRequestParameter(HttpServletRequest request, String parameter)
    {
        String str = request.getParameter(parameter);
        return str == null ? EMPTY : str.trim();
    }
}