如何删除 Java OutOfMemoryError
How to remove Java OutOfMemoryError
我有一个程序可以获取非常大的 txt 数据并更改此 txt 数据中某些列的顺序。有关它的作用的更多详细信息,请参阅我的问题 。我使用带有地图的列表,我可以想象这对于 java 虚拟机来说太多了,因为 txt 文件有 400,000 个条目,但我不知道还能做什么。我用较小的 txt 文件尝试过,然后它工作正常。否则它会运行一个多小时然后我得到一个 OutOfMemoryError。
这是我的代码:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Final {
public static void main(String[] args) {
String path = "C:\\\\Users\\\\Ferid\\\\Downloads\\\\secdef\\\\secdef.txt";
File file = new File(path);
new Final().updateFile(file);
}
private void updateFile(File file) {
List<String> allRows = getAllRows(file);
String[] baseRow = allRows.get(0).split("\|");
List<String> columns = getBaseColumns(baseRow);
System.out.println(columns.size());
appendNewColumns(allRows, columns);
System.out.println(columns.size());
List<Map<String, String>> mapList = convertToMap(allRows, columns);
List<String> newList = new ArrayList<String>();
appendHeader(columns, newList);
appendData(mapList, newList, columns);
String toPath = "C:\\\\Users\\\\Ferid\\\\Downloads\\\\secdef\\\\finalz2.txt";
writeToNewFile(newList, toPath);
}
/**
* Gibt alle Zeilen aus der Datei zurück.
*/
private static List<String> getAllRows(File file) {
List<String> allRows = new ArrayList<>();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String row = null;
int i = 0;
while ((row = reader.readLine()) != null) {
allRows.add(row);
}
} catch (IOException e) {
e.printStackTrace();
}
return allRows;
}
/**
* Gibt die Hauptspalten aus der 1. Zeile zurück.
*/
private static List<String> getBaseColumns(String[] baseRow) {
List<String> columns = new ArrayList<>();
for (String rowEntry : baseRow) {
String[] entry = rowEntry.split("=");
columns.add(entry[0]);
}
return columns;
}
/**
* Fügt alle neuen Spalten hinzu.
*/
private static void appendNewColumns(List<String> rows, List<String> columns) {
for (String row : rows) {
String[] splittedRow = row.split("\|");
for (String column : splittedRow) {
String[] entry = column.split("=");
if (columns.contains(entry[0])) {
continue;
}
columns.add(entry[0]);
}
}
}
/**
* Konvertiert die Listeneinträge zu Maps.
*/
private static List<Map<String, String>> convertToMap(List<String> rows, List<String> columns) {
List<Map<String, String>> mapList = new ArrayList<>();
for (String row : rows) {
Map<String, String> map = new TreeMap<>();
String[] splittedRow = row.split("\|");
List<String> rowList = Arrays.asList(splittedRow);
for (String col : columns) {
String newCol = findByColumn(rowList, col);
if (newCol == null) {
map.put(col, "null");
} else {
String[] arr = newCol.split("=");
map.put(col, arr[1]);
}
}
mapList.add(map);
}
return mapList;
}
/**
*
*/
private static String findByColumn(List<String> row, String col) {
return row.stream().filter(o -> o.startsWith(col)).findFirst().orElse(null);
}
/**
* Fügt die Header-Zeile in die neue Liste hinzu.
*/
private static void appendHeader(List<String> columns, List<String> list1) {
String header = "";
for (String column : columns) {
header += column + "|";
}
list1.add(header + "\n");
}
/**
* Fügt alle Daten in die entsprechenden neuen Dateien hinzu.
*/
private static void appendData(List<Map<String, String>> mapList, List<String> list1, List<String> columns) {
for (Map<String, String> entry : mapList) {
String line = "";
for (String key : columns) {
// for (String key : entry.keySet()) {
line += entry.get(key) + "|";
}
list1.add(line + "\n");
}
}
/**
* Schreibt alle Werte in die neue Datei.
*/
private static void writeToNewFile(List<String> list, String path) {
FileOutputStream out = null;
try {
out = new FileOutputStream(new File(path));
for (String line : list) {
out.write(line.getBytes());
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
您可以通过specyfying指定JVM可以使用的最大内存:-Xmx
例如。 -Xmx8G
,
使用 M 或 G
我们无法就分配的内存量给出具体的建议,因为这在很大程度上取决于您的服务器设置、用户群的规模及其行为。您需要找到适合您的值,即没有明显的 GC 暂停,也没有 OutOfMemory 错误。
供参考,用于更改内存(堆)分配的 3 个最常用参数是:
- Xms - the minimum size of the heap
- Xmx - the maximum size of the heap
- XX:MaxPermSize - the maximum size of PermGen (this is not used in Java 8 and above)
如果您决定增加内存设置,请遵循一些通用准则。
- 以小增量增加 Xmx(例如一次增加 512mb),直到你不
不再遇到 OutOfMemory 错误。这是因为增加
超出服务器能力的堆足以垃圾
收集可能会导致其他问题(例如performance/freezing)
- 如果你的错误是java。浪。 OutOfMemoryError : PermGen space,
以 256mb 的增量增加 -XX:MaxPermSize 参数,直到
错误停止发生。
- 如果你的错误没有引用PermGen,就没有必要
增加它。简单的解释,PermGen是用来存储
类,并且通常大小相当静态,已被删除
在 Java 8. 更多信息请点击此处。考虑将 Xms 和 Xmx 设置为相同
值,因为这可以减少 GC 发生的时间,因为它会
不要尝试在每个集合上调整堆的大小。
如果您在 Windows 上启动 Confluence 作为服务,那么您不应该使用这些说明。相反,请参阅下面的 "Windows Service" 部分。
如果您是通过批处理文件启动 Confluence,您应该只遵循这些说明。 Confluence 作为服务启动时不使用批处理文件。
从 .bat
文件启动时在 Windows 安装中配置系统属性,
- 关闭 Confluence
- 从 /bin(独立)或 /bin(EAR-WAR 安装),打开
setenv.bat
.
- 找到部分
CATALINA_OPTS="-Xms1024m -Xmx1024m -XX:+UseG1GC $CATALINA_OPTS" in Confluence 5.8 or above
CATALINA_OPTS="$CATALINA_OPTS -Xms1024m -Xmx1024m -XX:MaxPermSize=256m -XX:+UseG1GC" in Confluence 5.6 or 5.7
JAVA_OPTS="-Xms256m -Xmx512m -XX:MaxPermSize=256m in previous versions
- Xmx最大,Xms最小,MaxPermSize为PermGen。
- 启动 Confluence
在这种情况下,如果可能的话,逐行读取文件并分别处理每一行,而不是将整个文件保存在内存中是有意义的。
目前您的代码如下所示:
- 将所有行读入列表 L
- 为 L 中的每一行查找所有列
- 将 L 中的行转换为地图(在地图中使用 "null" 字符串而不是不设置值!!这可能是最后真正咬你的东西!)
- 将地图序列化为行
我调用 bs 只是为了增加可用内存,然后它稍后就会失败。您在这里遇到内存使用和性能方面的一般问题。让我提出一个不同的方式:
1. for each line read (don't read the whole file at once!):
1.1 find columns, collect in List C
2. for each line read (again, don't read the whole file at once, do it as you read):
2.2 for each column in C, write value if the row contains it, or null
2.3 append to the result file (also don't keep the result in memory!)
有点像这样:
BufferedReader reader = null;
BufferedWriter writer = null;
try {
reader = new BufferedReader(new FileReader(file));
String row = null;
int i = 0;
List<String> columns = new ArrayList<>();
while ((row = reader.readLine()) != null) {
columns.addAll(getColumns(row));
}
reader = new BufferedReader(new FileReader(file));
writer = new BufferedWriter(new FileWriter(outFile));
int i = 0;
while ((row = reader.readLine()) != null) {
writeRow(row, columns, writer);
}
} catch (IOException e) {
e.printStackTrace();
}
我有一个程序可以获取非常大的 txt 数据并更改此 txt 数据中某些列的顺序。有关它的作用的更多详细信息,请参阅我的问题
这是我的代码:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Final {
public static void main(String[] args) {
String path = "C:\\\\Users\\\\Ferid\\\\Downloads\\\\secdef\\\\secdef.txt";
File file = new File(path);
new Final().updateFile(file);
}
private void updateFile(File file) {
List<String> allRows = getAllRows(file);
String[] baseRow = allRows.get(0).split("\|");
List<String> columns = getBaseColumns(baseRow);
System.out.println(columns.size());
appendNewColumns(allRows, columns);
System.out.println(columns.size());
List<Map<String, String>> mapList = convertToMap(allRows, columns);
List<String> newList = new ArrayList<String>();
appendHeader(columns, newList);
appendData(mapList, newList, columns);
String toPath = "C:\\\\Users\\\\Ferid\\\\Downloads\\\\secdef\\\\finalz2.txt";
writeToNewFile(newList, toPath);
}
/**
* Gibt alle Zeilen aus der Datei zurück.
*/
private static List<String> getAllRows(File file) {
List<String> allRows = new ArrayList<>();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String row = null;
int i = 0;
while ((row = reader.readLine()) != null) {
allRows.add(row);
}
} catch (IOException e) {
e.printStackTrace();
}
return allRows;
}
/**
* Gibt die Hauptspalten aus der 1. Zeile zurück.
*/
private static List<String> getBaseColumns(String[] baseRow) {
List<String> columns = new ArrayList<>();
for (String rowEntry : baseRow) {
String[] entry = rowEntry.split("=");
columns.add(entry[0]);
}
return columns;
}
/**
* Fügt alle neuen Spalten hinzu.
*/
private static void appendNewColumns(List<String> rows, List<String> columns) {
for (String row : rows) {
String[] splittedRow = row.split("\|");
for (String column : splittedRow) {
String[] entry = column.split("=");
if (columns.contains(entry[0])) {
continue;
}
columns.add(entry[0]);
}
}
}
/**
* Konvertiert die Listeneinträge zu Maps.
*/
private static List<Map<String, String>> convertToMap(List<String> rows, List<String> columns) {
List<Map<String, String>> mapList = new ArrayList<>();
for (String row : rows) {
Map<String, String> map = new TreeMap<>();
String[] splittedRow = row.split("\|");
List<String> rowList = Arrays.asList(splittedRow);
for (String col : columns) {
String newCol = findByColumn(rowList, col);
if (newCol == null) {
map.put(col, "null");
} else {
String[] arr = newCol.split("=");
map.put(col, arr[1]);
}
}
mapList.add(map);
}
return mapList;
}
/**
*
*/
private static String findByColumn(List<String> row, String col) {
return row.stream().filter(o -> o.startsWith(col)).findFirst().orElse(null);
}
/**
* Fügt die Header-Zeile in die neue Liste hinzu.
*/
private static void appendHeader(List<String> columns, List<String> list1) {
String header = "";
for (String column : columns) {
header += column + "|";
}
list1.add(header + "\n");
}
/**
* Fügt alle Daten in die entsprechenden neuen Dateien hinzu.
*/
private static void appendData(List<Map<String, String>> mapList, List<String> list1, List<String> columns) {
for (Map<String, String> entry : mapList) {
String line = "";
for (String key : columns) {
// for (String key : entry.keySet()) {
line += entry.get(key) + "|";
}
list1.add(line + "\n");
}
}
/**
* Schreibt alle Werte in die neue Datei.
*/
private static void writeToNewFile(List<String> list, String path) {
FileOutputStream out = null;
try {
out = new FileOutputStream(new File(path));
for (String line : list) {
out.write(line.getBytes());
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
您可以通过specyfying指定JVM可以使用的最大内存:-Xmx
例如。 -Xmx8G
,
使用 M 或 G
我们无法就分配的内存量给出具体的建议,因为这在很大程度上取决于您的服务器设置、用户群的规模及其行为。您需要找到适合您的值,即没有明显的 GC 暂停,也没有 OutOfMemory 错误。
供参考,用于更改内存(堆)分配的 3 个最常用参数是:
- Xms - the minimum size of the heap
- Xmx - the maximum size of the heap
- XX:MaxPermSize - the maximum size of PermGen (this is not used in Java 8 and above)
如果您决定增加内存设置,请遵循一些通用准则。
- 以小增量增加 Xmx(例如一次增加 512mb),直到你不 不再遇到 OutOfMemory 错误。这是因为增加 超出服务器能力的堆足以垃圾 收集可能会导致其他问题(例如performance/freezing)
- 如果你的错误是java。浪。 OutOfMemoryError : PermGen space, 以 256mb 的增量增加 -XX:MaxPermSize 参数,直到 错误停止发生。
- 如果你的错误没有引用PermGen,就没有必要 增加它。简单的解释,PermGen是用来存储 类,并且通常大小相当静态,已被删除 在 Java 8. 更多信息请点击此处。考虑将 Xms 和 Xmx 设置为相同 值,因为这可以减少 GC 发生的时间,因为它会 不要尝试在每个集合上调整堆的大小。
如果您在 Windows 上启动 Confluence 作为服务,那么您不应该使用这些说明。相反,请参阅下面的 "Windows Service" 部分。
如果您是通过批处理文件启动 Confluence,您应该只遵循这些说明。 Confluence 作为服务启动时不使用批处理文件。
从 .bat
文件启动时在 Windows 安装中配置系统属性,
- 关闭 Confluence
- 从 /bin(独立)或 /bin(EAR-WAR 安装),打开
setenv.bat
. - 找到部分
CATALINA_OPTS="-Xms1024m -Xmx1024m -XX:+UseG1GC $CATALINA_OPTS" in Confluence 5.8 or above
CATALINA_OPTS="$CATALINA_OPTS -Xms1024m -Xmx1024m -XX:MaxPermSize=256m -XX:+UseG1GC" in Confluence 5.6 or 5.7
JAVA_OPTS="-Xms256m -Xmx512m -XX:MaxPermSize=256m in previous versions
- Xmx最大,Xms最小,MaxPermSize为PermGen。
- 启动 Confluence
在这种情况下,如果可能的话,逐行读取文件并分别处理每一行,而不是将整个文件保存在内存中是有意义的。
目前您的代码如下所示:
- 将所有行读入列表 L
- 为 L 中的每一行查找所有列
- 将 L 中的行转换为地图(在地图中使用 "null" 字符串而不是不设置值!!这可能是最后真正咬你的东西!)
- 将地图序列化为行
我调用 bs 只是为了增加可用内存,然后它稍后就会失败。您在这里遇到内存使用和性能方面的一般问题。让我提出一个不同的方式:
1. for each line read (don't read the whole file at once!):
1.1 find columns, collect in List C
2. for each line read (again, don't read the whole file at once, do it as you read):
2.2 for each column in C, write value if the row contains it, or null
2.3 append to the result file (also don't keep the result in memory!)
有点像这样:
BufferedReader reader = null;
BufferedWriter writer = null;
try {
reader = new BufferedReader(new FileReader(file));
String row = null;
int i = 0;
List<String> columns = new ArrayList<>();
while ((row = reader.readLine()) != null) {
columns.addAll(getColumns(row));
}
reader = new BufferedReader(new FileReader(file));
writer = new BufferedWriter(new FileWriter(outFile));
int i = 0;
while ((row = reader.readLine()) != null) {
writeRow(row, columns, writer);
}
} catch (IOException e) {
e.printStackTrace();
}