java 添加到 stringBuilder 时出现堆错误
java heap error when append to stringBuilder
在我的程序中我想读取一个 PLSQL 文件
并删除以--
开头的评论
我将每条评论都放在它自己的行中,这样我就可以删除该特定行(有时我将代码和评论放在同一行中,这就是我正在做的“\n--”)。
我将我的程序导出到一个 jar 文件,它在我的桌面上运行良好,但在另一台计算机上(读取不同的 PLSQL 文件)它给我 Java 堆 space 错误,即使我尝试
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"
结果是:最小值:16M 和最大尺寸:256M
所以我应该在 java -jar :-Xmx512m 而不是 -Xms256m
2-)
我删除了(仅用于测试)stringbuilder 和所有 replaceAll,但仍然出现相同的错误,因为我的文件太大了。
所以我所做的是计算我正在阅读的每个文件的行数,并尝试(取决于行数)例如仅读取前 50 行并将我的方法仅应用于这 50 行
谢谢大家的回答
您正在使用:
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::join and FileUtils::LineIterator 来获得相同的结果。希望这能解决问题。
编辑
根据 Nicolas Filotto 建议,我在一定数量的处理行之后添加了写入文件(该数字完全是随机选择的)。我测试了这两种方法,第一种方法因文件大小接近堆大小而失败(字符串中的行连接与 OP 代码存在相同的问题)。使用第二种方法,我用一个 2GB 的文件进行了测试,在执行 2 分钟后,我在输入文件旁边得到了 ${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);
}
}
假设您的 PLSQL
文件是 巨大的 ,您这里的问题可能是因为您加载 the entire file into memory
这不是一个好的方法在这种情况下,您应该逐行 read
并将结果 write
放入 temporary file
而不是将内容作为 String
返回。
写起来有点复杂,但它是一种更具可扩展性的方法,事实上,假设今天你将堆大小增加到 4Go,明天文件大两倍,你会把堆大小加倍吗?
在我的程序中我想读取一个 PLSQL 文件
并删除以--
开头的评论
我将每条评论都放在它自己的行中,这样我就可以删除该特定行(有时我将代码和评论放在同一行中,这就是我正在做的“\n--”)。
我将我的程序导出到一个 jar 文件,它在我的桌面上运行良好,但在另一台计算机上(读取不同的 PLSQL 文件)它给我 Java 堆 space 错误,即使我尝试
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"
结果是:最小值:16M 和最大尺寸:256M 所以我应该在 java -jar :-Xmx512m 而不是 -Xms256m
2-) 我删除了(仅用于测试)stringbuilder 和所有 replaceAll,但仍然出现相同的错误,因为我的文件太大了。
所以我所做的是计算我正在阅读的每个文件的行数,并尝试(取决于行数)例如仅读取前 50 行并将我的方法仅应用于这 50 行
谢谢大家的回答
您正在使用:
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::join and FileUtils::LineIterator 来获得相同的结果。希望这能解决问题。
编辑
根据 Nicolas Filotto 建议,我在一定数量的处理行之后添加了写入文件(该数字完全是随机选择的)。我测试了这两种方法,第一种方法因文件大小接近堆大小而失败(字符串中的行连接与 OP 代码存在相同的问题)。使用第二种方法,我用一个 2GB 的文件进行了测试,在执行 2 分钟后,我在输入文件旁边得到了 ${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);
}
}
假设您的 PLSQL
文件是 巨大的 ,您这里的问题可能是因为您加载 the entire file into memory
这不是一个好的方法在这种情况下,您应该逐行 read
并将结果 write
放入 temporary file
而不是将内容作为 String
返回。
写起来有点复杂,但它是一种更具可扩展性的方法,事实上,假设今天你将堆大小增加到 4Go,明天文件大两倍,你会把堆大小加倍吗?