簡體   English   中英

追加到stringBuilder時出現Java堆錯誤

[英]java heap error when append to stringBuilder

在我的程序中,我想讀取一個PLSQL文件並刪除以-開頭的注釋
我將每個注釋放在其自己的行中,以便刪除該特定行(有時我在同一行中具有代碼和注釋,這與我執行“ \\ n--”的方式相同)。
我將程序導出到jar文件,並且在我的桌面上可以正常工作,但在另一台計算機上(讀取不同的PLSQL文件),即使我嘗試,它也會給我Java堆空間錯誤

java -Xmx256m -jar myjar.jar

錯誤:

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)

Caused by: java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.lang.AbstractStringBuilder.expandCapacity(Unknown Source)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(Unknown Source)
    at java.lang.AbstractStringBuilder.append(Unknown Source)
    at java.lang.StringBuffer.append(Unknown Source)
    at ParserDB.ScriptNoComment(ParserDB.java:142)
    at ParserDB.GetTheName(ParserDB.java:54)
    at Rapport.SearchCcInDB(Rapport.java:189)
    at Rapport.listDB(Rapport.java:77)
    at Rapport.main(Rapport.java:472)
    ... 5 more

我的代碼是:

public static String ScriptNoComment(String fileName){
    String result = null ;      
    try{
        FileInputStream fstream = new FileInputStream(fileName);
        DataInputStream in = new DataInputStream(fstream);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        StringBuffer strOut = new StringBuffer();
        StringBuilder Out = new StringBuilder();
        String strLine;

         while ((strLine = br.readLine()) != null)   {

            if(strLine.contains("--")){
                strLine = strLine.replaceAll("--","\n--");
            }
            strOut.append(strLine+"\n");
        }

        in.close();   
        //delete comment
        String[] lines = strOut.toString().split("\\n");
        for(String s: lines){
            if(s.contains("--")){
                s="";
            }
            Out.append(s+"\n");
        }

        result = Out.toString();
        result = result.toUpperCase();      
        result = result.replaceAll("\"", "");
        result = result.replaceAll("\\r\\n|\\r|\\n", " ");
        result = result.replaceAll("\\s+", " ");

        }catch (Exception e){          
       System.err.println("Error: " + e.getMessage());
      }

    return result ;

}

無論如何有優化我的代碼,在此先感謝

編輯
1-)我使用以下命令在另一台計算機上檢查了堆大小:

java -XX:+ PrintFlagsFinal -version | findstr / i“ HeapSize PermSize ThreadStackSize”

結果是:min:16M和Maxsize:256M,所以我應該用java -jar:-Xmx512m代替-Xms256m

2-)我刪除了(僅用於測試)stringbuilder和所有replaceAll,但由於我的文件太大而仍然遇到相同的錯誤。

所以我要做的是計算我正在讀取的每個文件的行數,並嘗試(取決於行數)例如僅讀取前50行並將我的方法僅應用於這50行

謝謝大家的答案

假設你的PLSQL文件是巨大的 ,在這里你的問題很可能是由於您加載其實the entire file into memory這是不是在這種情況下,很好的方法,你應該read一行行,並write結果到一個temporary file而不是將內容作為String返回。

編寫起來有點復雜,但實際上它是一種更具可伸縮性的方法,可以說今天您將堆大小增加到4Go,明天文件又大兩倍,您會把堆大小增加一倍嗎?

您正在使用:

    strLine = strLine.replaceAll("--","\n--");

然后您要寫入String Buffer,然后寫入String Builder。

由於您只想刪除這些注釋,因此請替換

    if(strLine.contains("--")){
        strLine = strLine.replaceAll("--","\n--");
     }
    strOut.append(strLine+"\n");

    int chk=strLine.indexOf("--");
      if(chk!=-1)
        strLine = strLine.subtring(0,chk);
    Out.append(strLine +"\n");

希望這可以解決您的問題,因為您將不會使用StringBuffer並占用更少的內存。

如果您有Java 8,則可以在處理這些行時嘗試使用此代碼進行行內編輯

public static String scriptNoComment(String fileName) {

  Path filePath = Paths.get(fileName);
  try (Stream<String> stream = Files.lines(filePath)) {

    List<String> linesWithNoComments = new ArrayList<String>();

    stream.forEach(line -> {

      if (line.startsWith("--")) {
        return;
      }

      String currentLine = line;

      int commentStartIndex = line.indexOf("--");
      if (commentStartIndex != -1) {
        currentLine = line.substring(0, commentStartIndex);
      }

      currentLine = currentLine.toUpperCase();
      currentLine = currentLine.replaceAll("\"", "");
      currentLine = currentLine.replaceAll("\\r\\n|\\r|\\n", " ");
      currentLine = currentLine.replaceAll("\\s+", " ").trim();

      if (currentLine.isEmpty()) {
        return;
      }

      linesWithNoComments.add(currentLine);

    });

    return String.join("\n", linesWithNoComments);

  } catch (IOException e) {
    e.printStackTrace(System.out);
    return "";
  }
}

如果不能使用Java 8,則可以使用Apache StringUtils :: joinFileUtils :: LineIterator達到相同的結果。 希望這能解決問題。

編輯

根據Nicolas Filotto的建議,我在一定數量的處理過的行之后將寫入文件添加到文件中(該數目完全隨機選擇)。 我測試了這兩種方法,第一種方法失敗了,其文件大小接近堆大小(字符串中的行連接與OP代碼存在相同的問題)。 使用第二種方法,我測試了一個2GB的文件,執行2 ${fileName}_noComments ,在輸入文件旁邊有${fileName}_noComments文件。

public static int LINES_BATCH = 10000;

private static void scriptNoComment(String fileName) {

  Path filePath = Paths.get(fileName);
  try (Stream<String> stream = Files.lines(filePath); BufferedWriter fileOut = getFileOutWriter(fileName)) {

    List<String> linesWithNoComments = new ArrayList<String>();

    stream.forEach(line -> {

      if (line.startsWith("--")) {
        return;
      }

      String currentLine = line;

      int commentStartIndex = line.indexOf("--");
      if (commentStartIndex != -1) {
        currentLine = line.substring(0, commentStartIndex);
      }

      currentLine = currentLine.toUpperCase();
      currentLine = currentLine.replaceAll("\"", "");
      currentLine = currentLine.replaceAll("\\r\\n|\\r|\\n", " ");
      currentLine = currentLine.replaceAll("\\s+", " ").trim();

      if (currentLine.isEmpty()) {
        return;
      }

      linesWithNoComments.add(currentLine);

      if (linesWithNoComments.size() >= LINES_BATCH) {
        writeCurrentBatchToFile(fileOut, linesWithNoComments);
      }

    });

  } catch (IOException e) {
    e.printStackTrace(System.err);
  }
}

private static BufferedWriter getFileOutWriter(String fileName) {
  BufferedWriter fileOut;
  try {
    fileOut = new BufferedWriter(new FileWriter(fileName + "_noComments", false));
    return fileOut;
  } catch (IOException e) {
    throw new RuntimeException("Error while creating out writer", e);
  }
}

private static void writeCurrentBatchToFile(BufferedWriter fileOut, List<String> linesWithNoComments) {
  try {

    for (String line : linesWithNoComments) {
      fileOut.write(line + " ");
    }

    linesWithNoComments.clear();
  } catch(IOException e) {
    throw new RuntimeException("Unable to write lines to file", e);
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM