Java 循环通过中等大小数据集时Kotlin内存不足错误

Java 循环通过中等大小数据集时Kotlin内存不足错误,java,memory,kotlin,jvm,out-of-memory,Java,Memory,Kotlin,Jvm,Out Of Memory,我正在Kotlin中运行下面的循环,并抛出内存不足错误。我运行此命令是为了读取csv文件中的行。“记录”的大小为6422 我有同样的逻辑在Java中执行,但它工作得很好。下面是我在Java中的内容 private static List<String> readCSVFile(String filePath) throws IOException { Reader in = new FileReader(filePath); Iterable<CSVRecord

我正在Kotlin中运行下面的循环,并抛出内存不足错误。我运行此命令是为了读取csv文件中的行。“记录”的大小为6422

我有同样的逻辑在Java中执行,但它工作得很好。下面是我在Java中的内容

private static List<String> readCSVFile(String filePath) throws IOException {
    Reader in = new FileReader(filePath);
    Iterable<CSVRecord> records = CSVFormat.DEFAULT.parse(in);
    List<String> rows = new ArrayList<>();
    for (CSVRecord record : records) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < record.size(); i++)
            builder.append(record.get(i) + ",");
        builder.deleteCharAt(builder.length() - 1);
        rows.add(builder.toString());
    }
    return rows;
}
private static List readCSVFile(字符串文件路径)引发IOException{
Reader in=新文件读取器(文件路径);
Iterable records=CSVFormat.DEFAULT.parse(in);
列表行=新建ArrayList();
用于(CSVRecord记录:记录){
StringBuilder=新的StringBuilder();
对于(int i=0;i

为什么Kotlin对此有问题?我是不是在循环方面出了问题?任何帮助都将不胜感激,因为我是Kotlin的新手。

我认为您的代码中有一个bug

records.forEach() {
    output = "" // clear output ;)
    ...
}
将其与java代码进行比较

for (CSVRecord record : records) {
    StringBuilder builder = new StringBuilder(); // clear builder
    ...
}

在kotlin代码中也使用
StringBuilder
。您正在创建堆中
String
对象的日志。字符串是不可变的,此代码:

var output = ""
output = output + ","
正在堆中创建两个对象,尽管您只能引用其中一个对象。因此,另一个符合GC删除它的条件。在您的情况下,GC“工作”太辛苦了,这就是为什么您会得到
java.lang.OutOfMemoryError:超出了GC开销限制

fun readCSVFile(filePath: String): List<String> {
    val reader = FileReader(filePath)
    val records = CSVFormat.DEFAULT.parse(reader)
    val rows = mutableListOf<String>()

    var output = StringBuilder("")
    records.forEach() {
        output = StringBuilder("")
        val size = it.size()
        for (i in 0 until it.size()-1) {
            output = output.append(it.get(i) + ",")
        }
        output.deleteCharAt(output.length - 1)
        rows.add(output.toString())
    }
    return rows
}
fun readCSVFile(文件路径:字符串):列表{
val reader=FileReader(filePath)
val records=CSVFormat.DEFAULT.parse(读取器)
val rows=mutableListOf()
变量输出=StringBuilder(“”)
forEach()记录{
输出=StringBuilder(“”)
val size=it.size()
for(在0中输入i,直到它.size()-1){
output=output.append(it.get(i)+“,”)
}
output.deleteCharAt(output.length-1)
rows.add(output.toString())
}
返回行
}

您的代码运行速度也会快得多,因为创建新对象的成本相当高。

您的Kotlin代码中有两个问题:

  • 您正在使用字符串和字符串连接-这是一个代价高昂的操作。您还应该使用StringBuilder
  • 您正在foreach循环外部设置
    output=“
    ”——对于每个迭代,您的输出中都有以前的所有行

  • 您正在阅读的CSV大小是多少?你的JVM的-Xmx值是多少(如果你自己定义的话)?对不起,我编辑了这个问题。是6422字节吗?另外,您是否在任何地方定义了-Xmx或它是默认值?我想答案已经解决了问题,所以这是为了解决另一个问题:将0中的
    I替换为it.size()-1
    ,将0中的
    I替换为it.size()
    I in 0..it.size()-1
    ,因为它丢失了最后一行。您尝试过吗?我不认为这会有帮助,因为OP的
    GC开销限制超过了
    ,这意味着heapI中有很多对象同意StringBuilder会有帮助,但这也会有帮助,因为这是GC必须运行那么多次的原因。rows.add(输出)->rows.add(“row1”);rows.add(输出)->rows.add(“row1row2”);rows.add(输出)->rows.add(“row1row2row3”);rows.add(输出)->rows.add(“row1row2row3…row6422”);这不会以任何方式影响GC运行
    行的时间。添加(输出)
    ,字符串只是不断变大,OP的错误字符串不断变大,堆内存不足,将导致GC运行。GC一直试图释放内存,但几乎无法完成任何工作,因为行内容不能被垃圾收集。
    var output = ""
    output = output + ","
    
    fun readCSVFile(filePath: String): List<String> {
        val reader = FileReader(filePath)
        val records = CSVFormat.DEFAULT.parse(reader)
        val rows = mutableListOf<String>()
    
        var output = StringBuilder("")
        records.forEach() {
            output = StringBuilder("")
            val size = it.size()
            for (i in 0 until it.size()-1) {
                output = output.append(it.get(i) + ",")
            }
            output.deleteCharAt(output.length - 1)
            rows.add(output.toString())
        }
        return rows
    }