读取大型文件进行模拟(Java崩溃,堆空间不足)

读取大型文件进行模拟(Java崩溃,堆空间不足),java,performance,io,Java,Performance,Io,对于学校作业,我需要创建一个内存访问模拟。首先,我需要读取一个或多个跟踪文件。每个包含每次访问的内存地址。例如: 0 F001CBAD 2 EEECA89F 0 EBC17910 ... 其中第一个整数表示读/写等,然后是十六进制内存地址。有了这些数据,我应该运行一个模拟。所以我的想法是将这些数据解析成一个ArrayList(现在我使用的是Java),trace是一个简单的类,包含内存地址和访问类型(只有一个字符串和一个整数)。之后,我计划遍历这些数组列表来处理它们 甚至在解析时也会出现问题,

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

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

甚至在解析时也会出现问题,因为它会耗尽堆空间。每个跟踪文件约为200MB。我有多达8个。这意味着我尝试“缓存”的数据至少为1.6GB?让我困惑的是,根据我的任务管理器,我只解析了1个文件,而java使用的是2GB

有什么更好的方法

可以在

中找到您应该在此处使用的代码段

但是,因为复制似乎没有问题,所以我将在这里复制答案


几乎可以肯定,问题在于
跟踪
类的结构,以及内存效率。您应该确保
instrType
hexAddress
存储为高效内存结构。instrType看起来是一个
int
,这很好,但只需确保它在跟踪类中声明为
int

更可能的问题是hexAddress字符串的大小。您可能没有意识到这一点,但字符串因“泄漏”内存而臭名昭著。在本例中,您有一个
,您认为您只是从中获取了hextstring。。。但实际上,十六进制字符串包含整行。。。。是的,真的。例如,请查看以下代码:

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);
    }
}
现在,在IDE(我使用eclipse)中设置一个断点,然后运行它,您将看到hexAddr包含一个用于整行的char[]数组,它的偏移量为3,计数为7

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

您至少应将代码更改为:

hexAddr = new String(tokenizer.nextToken().toCharArray());
但更好的是:

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

尝试使用class
java.nio.ByteBuffer
而不是
java.util.ArrayList
。它还应该减少内存使用

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)
    }

}

像罗尔夫一样,我在报告中回答了你的问题。对我来说,最大的问题是先将所有内容读入内存,然后再进行处理。你需要阅读一个固定的数量,处理它,然后重复直到完成。

没有看到它是一个SE站点,但即使是一个站点,你也应该提供更多的信息,这样答案就更完整了。谢谢你的工作做得很好,存储时间也很长。看起来字符串真的在泄漏。。。如果字符串有漏洞,是否应该在Java中修复?听起来好像没有采取任何措施来解决这个问题?在这种情况下,存储为long可以工作,但是其他方面呢?如果我需要存储相对较短的字符串,您推荐什么?在另一种语言中,这种情况也会发生吗?例如,在新字符串可以访问旧字符串内部的字符串对字符串操作中,Python或JavaScript?字符串仅会“泄漏”。在大多数情况下,这是对你有利的,考虑<代码>字符串行=“99瓶F啤酒”;<代码>然后
字符串ninenine=line.substring(0,2)
字符串bob=line.substring(3)
将占用更少的空间,因为它们都共享相同的
char[]
数组。问题是当您丢弃(并垃圾收集)
bob
变量时,在
ninenine
后面会留下一个过大的数组。变量。要执行其余操作,您需要在内存中保留所有行,还是可以在读取后处理该行,然后丢弃
跟踪
对象?