读取大型文件进行模拟(Java崩溃时没有堆空间)

时间:2013-11-07 12:42:22

标签: java performance io

对于学校作业,我需要创建一个内存访问模拟。首先,我需要读取一个或多个跟踪文件。每个包含每次访问的内存地址。示例:

0 F001CBAD
2 EEECA89F
0 EBC17910
...

第一个整数表示读/写等,然后是十六进制存储器地址。有了这些数据,我应该进行模拟。所以我的想法是将这些数据解析为ArrayList<Trace>(现在我正在使用Java),trace是一个包含内存地址和访问类型的简单类(只是一个字符串和一个整数)。之后我计划遍历这些数组列表来处理它们。

问题甚至在解析时,它耗尽了堆空间。每个跟踪文件大约200MB。我最多8个。意思是最小的~1.6 GB的数据我试图&#34;缓存&#34;?令我感到困惑的是,根据我的任务经理,我只解析了1个文件而java正在使用2GB ......

这样做的更好方法是什么?

可以在Code Review

找到代码段

3 个答案:

答案 0 :(得分:1)

The answer I gave on codereview is the same你应该在这里使用.....

但是,因为重复似乎没问题,我会在这里复制答案。


问题几乎可以肯定是Trace类的结构,而且是内存效率。您应确保将instrTypehexAddress存储为内存有效结构。 instrType似乎是int,这很好,但只要确保它在Trace类中声明为int

更可能的问题是hexAddress String的大小。你可能没有意识到这一点,但是Strings因“泄漏”记忆而臭名昭着。在这种情况下,你有一个line并且你认为你只是从中获取hexString ......但实际上,hexString包含整行......是的,真的。例如,请查看以下代码:

public class SToken {

    public static void main(String[] args) {
        StringTokenizer tokenizer = new StringTokenizer("99 bottles of beer");
        int instrType = Integer.parseInt(tokenizer.nextToken());
        String hexAddr = tokenizer.nextToken();
        System.out.println(instrType + hexAddr);
    }
}

现在,设置一个断点(我使用eclipse)你的IDE,然后运行它,你会看到hexAddr包含整个行的char []数组,它的偏移量为3和a数为7。

由于String子串和其他构造的工作方式,它们可以为短字符串消耗大量内存......(理论上,内存与其他字符串共享)。因此,您实际上是将整个文件存储在内存中!!!!

至少应将代码更改为:

hexAddr = new String(tokenizer.nextToken().toCharArray());

但更好的是:

long hexAddr = parseHexAddress(tokenizer.nextToken());

答案 1 :(得分:1)

就像rolfl一样,我在code review回答了你的问题。对我来说,最大的问题是先将所有内容读入内存然后再处理。您需要读取固定金额,处理,然后重复直到完成。

答案 2 :(得分:0)

尝试使用课程java.nio.ByteBuffer代替java.util.ArrayList<Trace>。它还应该减少内存使用量。

class TraceList {

    private ByteBuffer buffer;

    public TraceList(){
        //allocate byte buffer
    }

    public void put(byte operationType, int addres) {
        //put data to byte buffer
    }

    public Trace get(int index) {
        //get data from byte buffer by index
        byte type = ...//read type
        int addres = ...//read addres
        return new Trace(type, addres)
    }

}