0

我正在尝试从文件(运行 10 分钟的 10 个线程)中读取大量数据(10k-20k 记录)。我得到一个例外:

Exception in thread "main" Exception in thread "Thread-26" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOfRange(Unknown Source)
    at java.lang.String.<init>(Unknown Source)
    at java.io.BufferedReader.readLine(Unknown Source)
    at java.io.BufferedReader.readLine(Unknown Source)

我收到以下代码片段的上述错误消息。我一直在尝试调试这个:我最接近的是使用 CharSequence。但我仍然得到堆异常。(此时 - 谁能帮我理解为什么 CharSequence 会更好?=> 似乎它会在主内存中加载少量数据,但最终所有数据都需要在主内存中)。

如果 1 分钟,我可以运行代码。但是任何接近 10 分钟的东西都会爆炸。有没有一种有效的方法来读取文件?

**此代码是研究的一部分,我仍在重构它,因此确实存在许多低效代码。

    try{
        for(int i=0; i<threadCount; i++){
            fstream = new FileInputStream(dir+"//read"+machineid+"-"+i + ".txt");
            // Use DataInputStream to read binary NOT text.
            BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
            String line;
            // Read File Line By Line
            String[] tokens;

            while ((line = br.readLine()) != null) {
                tokens = line.split(",");
                logObject record = new logObject(tokens[0], tokens[1], tokens[2],tokens[3], tokens[4], tokens[5], tokens[6], tokens[7], "", tokens[8]);
                toBeProcessed[toBeProcessedArraySz] = record;
                toBeProcessedArraySz++;
                if(readToValidate == toBeProcessedArraySz){

                    try {
                        semaphore.acquire();
                    } catch (InterruptedException e) {
                        e.printStackTrace(System.out);
                    }
                    //create thread to process the read records
                    ValidationThread newVThread = new ValidationThread(props,toBeProcessed, updateStats, initCnt, semaphore, finalResults, staleSeqSemaphore, staleSeqTracker, seqTracker, seenSeqSemaphore, toBeProcessedArraySz, freshnessBuckets,bucketDuration);
                    vThreads.add(newVThread);
                    toBeProcessedArraySz = 0;
                    toBeProcessed = new logObject[readToValidate];
                    semaphore.release();
                    newVThread.start();
                }                       
            }
            br.close();//remove to test
            fstream.close();                
        }

    }catch(Exception e){
        e.printStackTrace(System.out);
    }
4

2 回答 2

2

尝试用更大的堆空间启动JVM;那是电话java -Xmx=1G yourProgram。仅通过代码片段很难判断程序内存不足的原因。您还可以使用诸如 Eclipse MAT 之类的分析器工具来准确查看哪些对象导致内存已满。

于 2013-10-12T11:22:11.960 回答
2

如果您不了解问题,请不要简单地增加堆大小。增加堆大小并不能解决您的问题。它只会推迟它直到它变得更糟(需要更长的时间才能发生)。

问题是当堆已满时,您的程序不会等待读取数据。这是一个简单的问题。您的算法中没有任何内容可以阻止读取线程越来越多地填充堆。如果处理线程跟不上读取速度,OOME一定会在某个时候发生。您必须更改这一点:对于数据读取线程,添加某种方式,如果最大数量的处理线程处于活动状态,它会暂停读取,并在处理线程的数量再次低于此阈值时恢复读取数据。

此外:可能您的某个文件已损坏并且包含很长的一行,例如一行 > 500MB。找出 OOME 是否总是出现在同一行(很可能是这种情况),然后检查该行。它最后有什么线分隔符,\n或者\r\n?或者\r

于 2013-10-13T22:08:58.317 回答