Java上的堆内存问题
我正在尝试运行下面的程序,但在StringBuilder附加循环结构期间出现OutOfMemory错误Java上的堆内存问题,java,csv,memory-management,out-of-memory,heap-memory,Java,Csv,Memory Management,Out Of Memory,Heap Memory,我正在尝试运行下面的程序,但在StringBuilder附加循环结构期间出现OutOfMemory错误 我正在尝试做任何事情来降低内存使用率,使其足以读取CSV文件(超过200000行,但只有3列:item、rating、user) 然后,我将创建一个2D int数组,其中唯一的项表示 行、唯一用户表示列,交点为 评级 最后,我将使用StringBuilder帮助创建输出CSV文件 谢谢你的帮助和时间 List<String> userList = new ArrayLi
List<String> userList = new ArrayList<String>();
List<String> itemList = new ArrayList<String>();
FileInputStream stream = null;
Scanner scanner = null;
int[][] layout = new int[10672][24303];
int indexItemList = 0;
double temp = 0;
try{
stream = new FileInputStream(fileName);
scanner = new Scanner(stream, "UTF-8");
while (scanner.hasNextLine()){
String line = scanner.nextLine();
if (!line.equals("")){
String[] elems = line.split(",");
if (indexItemList == 0) {
temp = Double.valueOf(elems[1]);
layout[0][0] = (int)temp;
itemList.add(elems[0]);
userList.add(elems[2]);
indexItemList++;
}
else {
boolean itemFound = itemList.contains(elems[0]);
boolean userFound = userList.contains(elems[2]);
int indexItem = 1;
int indexUser = 1;
if ((itemFound) && (userFound)) {
indexItem = itemList.indexOf(elems[0]);
indexUser = userList.indexOf(elems[2]);
temp = Double.valueOf(elems[1]);
layout[indexItem][indexUser] = (int)temp;
}
else if ((itemFound) && (!userFound)) {
userList.add(elems[2]);
indexItem = itemList.indexOf(elems[0]);
indexUser = userList.indexOf(elems[2]);
temp = Double.valueOf(elems[1]);
layout[indexItem][indexUser] = (int)temp;
}
else if ((!itemFound) && (userFound)){
itemList.clear();
itemList.add(elems[0]);
indexUser = userList.indexOf(elems[2]);
temp = Double.valueOf(elems[1]);
layout[indexItemList][indexUser] = (int)temp;
indexItemList++;
}
else if (!((itemFound) && (userFound))) {
itemList.clear();
itemList.add(elems[0]);
userList.add(elems[2]);
indexUser = userList.indexOf(elems[2]);
temp = Double.valueOf(elems[1]);
layout[indexItem][indexUser] = (int)temp;
indexItemList++;
}
}
}
}
if (scanner.ioException() != null){
throw scanner.ioException();
}
}
catch (IOException e){
System.out.println(e);
}
finally{
try{
if (stream != null){
stream.close();
}
}
catch (IOException e){
System.out.println(e);
}
if (scanner != null){
scanner.close();
}
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < layout.length; i++){
for (int j = 0; j < layout[i].length; j++){
sb.append(layout[i][j] + "");
layout[i][j] = 0;
if (j < layout[i].length - 1){
sb.append(",");
}
}
sb.append("\n");
}
List userList=new ArrayList();
List itemList=new ArrayList();
FileInputStream=null;
扫描器=空;
int[][]布局=新int[10672][24303];
int indexItemList=0;
双温=0;
试一试{
stream=新文件输入流(文件名);
扫描仪=新扫描仪(流,“UTF-8”);
while(scanner.hasNextLine()){
字符串行=scanner.nextLine();
如果(!line.equals(“”){
String[]elems=line.split(“,”);
如果(indexItemList==0){
温度=两倍的值(元素[1]);
布局[0][0]=(内部)温度;
itemList.add(elems[0]);
userList.add(elems[2]);
indexItemList++;
}
否则{
布尔itemFound=itemList.contains(元素[0]);
布尔userFound=userList.contains(elems[2]);
int indexItem=1;
int indexUser=1;
if((itemFound)&(userFound)){
indexItem=itemList.indexOf(elems[0]);
indexUser=userList.indexOf(elems[2]);
温度=两倍的值(元素[1]);
布局[indexItem][indexUser]=(int)温度;
}
如果((itemFound)&(!userFound))为else{
userList.add(elems[2]);
indexItem=itemList.indexOf(elems[0]);
indexUser=userList.indexOf(elems[2]);
温度=两倍的值(元素[1]);
布局[indexItem][indexUser]=(int)温度;
}
如果((!itemFound)和(&&(userFound))为else{
itemList.clear();
itemList.add(elems[0]);
indexUser=userList.indexOf(elems[2]);
温度=两倍的值(元素[1]);
布局[indexItemList][indexUser]=(int)温度;
indexItemList++;
}
如果(!((itemFound)和(&(userFound)),则为else{
itemList.clear();
itemList.add(elems[0]);
userList.add(elems[2]);
indexUser=userList.indexOf(elems[2]);
温度=两倍的值(元素[1]);
布局[indexItem][indexUser]=(int)温度;
indexItemList++;
}
}
}
}
if(scanner.ioException()!=null){
抛出scanner.ioException();
}
}
捕获(IOE异常){
系统输出打印ln(e);
}
最后{
试一试{
if(流!=null){
stream.close();
}
}
捕获(IOE异常){
系统输出打印ln(e);
}
如果(扫描器!=null){
scanner.close();
}
}
StringBuilder sb=新的StringBuilder();
对于(int i=0;i
您的文件有200000行,但您的2D数组有259'361'616个单元格,并且StringBuilder
的大小将与该数字成比例。您不需要存储所有这些:它是一个非常空心的矩阵
下面是我要做的:在读取输入文件时,我将构建两个字符串集:items和users,以及一个将评级与每个(item,user)耦合关联的映射:
更新:
如果您对同一(项目、用户)对有多个评分,则只保留最后一个。您可以在地图中使用累加器
s而不是Double
s来计算平均值:
public class Accumulator {
private int count;
private double sum;
public void add(double value) {
sum += value;
++count;
}
public double getAverage() {
return count == 0 ? 0 : sum/count;
}
}
更新2:勘误表
StringBuilder的大小与矩阵的大小不成正比,而是与项目数乘以用户数成正比。
我正在解析的原始CSV文件超过200000行,正好有3列(用户、评级、项目)。我希望创建一个类似于所附照片的矩阵。原因是我计划稍后使用这个矩阵来计算两个矩阵行之间的余弦相似性(这将是该方法的输入)。基本上,我会比较第一行(userID#1)和第二行(userID#2)的所有评分。我认为您不需要该
StringBuilder
:您可以直接写入输出文件。您需要的最终CSV是什么?您是否试图为每个唯一的用户/项目组合写出一个值?要减少stringbuilder的内存占用,请经常写入文件,而不是尝试将整个csv保存在内存中。
try (OutputStream stream = new FileOutputStream(outputName);
Writer writer = new OutputStreamWriter(stream, "UTF-8");
PrintWriter out = new PrintWriter(writer)) {
for (String item: items) {
int j = 0;
for (String user: users) {
Double rating = ratings.get(item+','+user);
double r = rating == null ? 0 : rating;
out.print(r);
++j;
if (j < users.size()) {
out.print(',');
}
}
out.println();
}
} catch (IOException e) {
System.out.println(e);
}
public class Accumulator {
private int count;
private double sum;
public void add(double value) {
sum += value;
++count;
}
public double getAverage() {
return count == 0 ? 0 : sum/count;
}
}