Java-字节缓冲区内存不足

Java-字节缓冲区内存不足,java,file,memory,out-of-memory,Java,File,Memory,Out Of Memory,对Java来说有点陌生,但我已经能够很快地学到很多东西。尽管如此,仍然有很多方法让我无法理解。我正在编写一个Java程序,它将运行一组文件,并对它们进行彻底测试,以确定它们是否是有效的级别包文件。多亏了Matt Olenik和他的GobFile类(该类仅用于提取文件),我才能够想出一个好的策略,快速访问关卡包的重要部分和它们各自的地图文件,以确定各种细节。 但是,在37个文件(其中5个不是级别包)上测试时,它会在测试35个文件后崩溃。第35个文件是有效的级别包。它给出的错误是: 线程“main”

对Java来说有点陌生,但我已经能够很快地学到很多东西。尽管如此,仍然有很多方法让我无法理解。我正在编写一个Java程序,它将运行一组文件,并对它们进行彻底测试,以确定它们是否是有效的级别包文件。多亏了Matt Olenik和他的GobFile类(该类仅用于提取文件),我才能够想出一个好的策略,快速访问关卡包的重要部分和它们各自的地图文件,以确定各种细节。 但是,在37个文件(其中5个不是级别包)上测试时,它会在测试35个文件后崩溃。第35个文件是有效的级别包。它给出的错误是:

线程“main”java.lang.OutOfMemoryError中出现异常:java堆空间

     Iterator iter = itemList.keySet().iterator();
     numJKLs = 0;
     while (iter.hasNext()) {
        String nextFile = (String) iter.next();
        if (nextFile.startsWith("jkl\\")) {
           System.out.println(((ItemInfo) itemList.get(nextFile)).length);
-->        byte[] buffer = new byte[((ItemInfo) itemList.get(nextFile)).length];
           gobRaf.seek(((ItemInfo) itemList.get(nextFile)).offset);
           gobRaf.read(buffer, 0,
                 ((ItemInfo) itemList.get(nextFile)).length);
           String[] content = new String(buffer).toLowerCase().split(
                 "\n");
           levels.add(numJKLs, new JKLFile(theFile, nextFile, content));
           gametype = levels.get(numJKLs).getFileType();
           progress.setProgText(nextFile);
           buffer = null;
           content = null;
           numJKLs++;
        }
     }
箭头显示标记错误的位置。“JKLFile”类读取这些重要部分的
内容
数组,但(理论上)在完成后应该将其处理掉。像这里一样,我设置
content=null
JKLFile
中,以确保它已消失。如果您想知道它停止的映射文件有多大,那么,它成功地传递了一个17MB的映射文件,但这一个只有5MB

正如您所看到的,这些
JKLFile
对象保存在这个对象(
GobFile.java
)中,以便于以后访问,而
GobFile
对象则保存在另一个类中,以备以后访问,直到我更改了目录(尚未实现)。但是这些东西不应该装得太多。只是一个文件名和各种细节的列表

关于如何找出内存的去向或哪些对象使用的资源最多,有什么建议吗?当我从列表中单击详细信息时,最好将其保存在内存中,而不必再次加载文件(最多2秒)


/Edward现在您正在为每个循环创建一个新的缓冲区。根据您的垃圾收集情况,其中一些可能无法从内存中回收/释放,然后您的内存将耗尽。您可以使用
System.gc()
调用垃圾收集器,但不能保证它在任何给定的时间实际运行

使用
-Xmx
-Xms
参数调用程序时,可以在命令行上增加分配给JVM的内存。另外,如果您不在32位windows上,请确保您使用的是64位JVM,因为32位JVM有内存限制,而前者没有。从命令行运行
java-version
,查看当前系统JVM

您可以将byte[]缓冲区的声明移动到循环之外(在
while
上方),以便在每次迭代中清除并重用它

Iterator iter = itemList.keySet().iterator();
numJKLs = 0;
byte[] buffer;
while (iter.hasNext()) {
    ...
    buffer = new byte[] ...
    ...
}
您正在处理的文件有多大?您真的需要将它们中的每一个添加到您的
级别
变量中吗?你能用一些文件信息或统计数据来代替吗?您的JVM当前分配了多少RAM


要查看任何给定时间的当前内存使用情况,您需要在程序运行时进行调试。查看如何为您选择的IDE执行此操作,您将能够在程序的整个生命周期内跟踪任何对象的当前状态。

您正在将所有文件添加到
级别
?你认为会有多大程度的热舔?我不会把所有的东西都添加到
级别。是的,我正在发送内容,但我希望它不会被保存。只需处理关键细节并保存2个整数和2个字符串(级别名称和文件名)。在我看来,似乎您正在将每个文件的内容添加到
级别
--
级别。添加(numjlkls,新JKLFile(theFile,nextFile,content))。因此,您可以有效地一次将所有文件读入存储器(仅以您读取文件的方式,它们占用的空间可能是原始文件的5倍)。@HotLicks,我从整个层次包中的一个特定文件中得到的细节在文件的中间,在它之前有未知数量的声明和它后面的未知数量的东西。我尝试了
.readLine()
,但运行一些文件花了很长时间。这是迄今为止最快的策略。然后,您必须处理用所有这些数据填充堆的后果。显然,在
级别
对象中,每个文件的每一行都有。运行System.gc()将无法防止错误。增加堆大小只是隐藏了一个事实,即他一次读取所有文件会极大地浪费存储空间。好吧,实际上我并没有将整个
内容添加到我的
级别
变量中。是的,我正试图将
内容
发送给班级,但没想到会保存下来。只需处理关键细节并保存2个整数和2个字符串(级别名称和文件名)。然而,你的回答确实帮助我重新组织了我的变量。将
byte[]buffer
以及
String[]content
和一些其他变量移到循环之外,使程序完成了所有37个文件。你必须试着记住这一点。谢谢