即使我指定了足够大的 xmx,将文本文件加载到列表中时也会出现内存不足错误

发布于 2025-01-03 17:08:26 字数 2594 浏览 2 评论 0原文

当我尝试使用 -Xms32m -Xmx128m 加载列表中的 39MB 文本时,出现内存不足错误。所以我开始一点一点地增加Xmx,直到加载成功,发现我至少需要Xmx170m才能加载内存中的39MB文件

我想知道,为什么我需要这么大的内存?我尝试使用 UTF-8、UTF-16 和 UTF-32 计算列表中分配的内存量,但在出现内存不足异常时,它们似乎都不与 Xmx 匹配。那么计算分配的内存的正确方法是什么呢?

有人可以解释一下我在这里缺少什么吗?

以下是 at -Xms32m -Xmx128m 的输出和代码示例

Max memory 129 MB.
Total memory 32 MB.
Free memory 32 MB.
Input file size 39 MB.
Out Of Memory Error
List size in UFT-8 29 MB.
List size in UFT-16 58 MB.
List size in UFT-32 116 MB.
Free memory 4 MB.
End 

java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.ArrayList.ensureCapacity(Unknown Source)
    at java.util.ArrayList.add(Unknown Source)
    at com.nrx.util.SortUtil.main(SortUtil.java:288)



public static void main(String[] args)
{
    System.out.println("Max memory "+Runtime.getRuntime().maxMemory()/1000 /1000+" MB.");
    System.out.println("Total memory "+Runtime.getRuntime().totalMemory()/1000 /1000+" MB.");
    System.out.println("Free memory "+Runtime.getRuntime().freeMemory()/1000 /1000+" MB.");

    long utf8 = 0;
    long utf16 = 0;
    long utf32 = 0;
    List<String> strList = new ArrayList<String>();
    try 
    {
        File inFile = new File("data/input38.log");
        System.out.println("Input file size "+inFile.length()/1000 /1000+" MB.");
        BufferedReader fileReader = new BufferedReader(new FileReader(inFile));
        String line = fileReader.readLine();
        while (line != null)
        {
            utf8 = utf8 + line.getBytes("UTF-8").length;
            utf16 = utf16 + line.getBytes("UTF-16").length;
            utf32 = utf32 + line.getBytes("UTF-32").length;

            StringTokenizer st = new StringTokenizer(line, " ");
            while(st.hasMoreTokens())
                strList.add(st.nextToken().trim());
            line = fileReader.readLine();
        }

    } 
    catch (OutOfMemoryError e) 
    {
        System.out.println("Out Of Memory Error ");
        System.out.println("List size in UFT-8 "+utf8/1000 /1000+" MB.");
        System.out.println("List size in UFT-16 "+utf16/1000 /1000+" MB.");
        System.out.println("List size in UFT-32 "+utf32/1000 /1000+" MB.");
        System.out.println("Free memory "+Runtime.getRuntime().freeMemory()/1000 /1000+" MB.");
        e.printStackTrace();
    }
    catch (FileNotFoundException e) 
    {
        e.printStackTrace();
    } 
    catch (IOException e) 
    {
        e.printStackTrace();
    }
    System.out.println("End ");
}

I am getting out of memory error when I try to load a 39MB text in a List with -Xms32m -Xmx128m. so I started to increase the Xmx little by little until its loaded successfully and found out I need at least Xmx170m to load the 39MB file in the memory

I am wondering, why do I need such a large amount of memory? I try to calculate the amount of memory being allocated in the list using UTF-8, UTF-16 and UTF-32 but none of them seem to match the Xmx at the point where is get the out of memory exception. So what is the correct way to calculate the allocated memory?

Can someone please explain what am I missing here?

Below is the output and code sample with at -Xms32m -Xmx128m

Max memory 129 MB.
Total memory 32 MB.
Free memory 32 MB.
Input file size 39 MB.
Out Of Memory Error
List size in UFT-8 29 MB.
List size in UFT-16 58 MB.
List size in UFT-32 116 MB.
Free memory 4 MB.
End 

java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.ArrayList.ensureCapacity(Unknown Source)
    at java.util.ArrayList.add(Unknown Source)
    at com.nrx.util.SortUtil.main(SortUtil.java:288)



public static void main(String[] args)
{
    System.out.println("Max memory "+Runtime.getRuntime().maxMemory()/1000 /1000+" MB.");
    System.out.println("Total memory "+Runtime.getRuntime().totalMemory()/1000 /1000+" MB.");
    System.out.println("Free memory "+Runtime.getRuntime().freeMemory()/1000 /1000+" MB.");

    long utf8 = 0;
    long utf16 = 0;
    long utf32 = 0;
    List<String> strList = new ArrayList<String>();
    try 
    {
        File inFile = new File("data/input38.log");
        System.out.println("Input file size "+inFile.length()/1000 /1000+" MB.");
        BufferedReader fileReader = new BufferedReader(new FileReader(inFile));
        String line = fileReader.readLine();
        while (line != null)
        {
            utf8 = utf8 + line.getBytes("UTF-8").length;
            utf16 = utf16 + line.getBytes("UTF-16").length;
            utf32 = utf32 + line.getBytes("UTF-32").length;

            StringTokenizer st = new StringTokenizer(line, " ");
            while(st.hasMoreTokens())
                strList.add(st.nextToken().trim());
            line = fileReader.readLine();
        }

    } 
    catch (OutOfMemoryError e) 
    {
        System.out.println("Out Of Memory Error ");
        System.out.println("List size in UFT-8 "+utf8/1000 /1000+" MB.");
        System.out.println("List size in UFT-16 "+utf16/1000 /1000+" MB.");
        System.out.println("List size in UFT-32 "+utf32/1000 /1000+" MB.");
        System.out.println("Free memory "+Runtime.getRuntime().freeMemory()/1000 /1000+" MB.");
        e.printStackTrace();
    }
    catch (FileNotFoundException e) 
    {
        e.printStackTrace();
    } 
    catch (IOException e) 
    {
        e.printStackTrace();
    }
    System.out.println("End ");
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

嗳卜坏 2025-01-10 17:08:26

我相信这是因为您使用的是 ArrayList。 ArrayList 是简单数组的智能包装。当列表增长时,ArrayList 创建新数组并将旧内容复制到新数组。首先,效率极低。其次,它每次都需要列表的三倍大小:旧数组中的 n 个元素和新数组中的 n*2 个元素。

因此,请尝试使用 LinkedList 来代替。我希望它对你有用。

I believe that this is because you are using ArrayList. ArrayList is at smart wrapper over simple array. When list is growing up ArrayList creates new array and copies the old content to the new one. First, it is extremely not efficient. Second, it requires at list triple size each time: n elements in old array and n*2 elements in the new one.

So, try to use LinkedList instead. I hope it will work for you.

離殇 2025-01-10 17:08:26

你正在使用ArrayList。所以它是一个基于数组的列表。如果不创建新的更大的数组,就无法更改数组的大小。需要分配新数组,并且需要将所有元素复制到更大的数组(留出一些空白空间,以使添加一定数量的元素不会那么繁重)。尝试使用具有指定数量元素的 String[] 表,以最小化其在内存中的大小并避免数组复制。

我不确定,但我认为在Java中,字符串中的字符总是16位?

而且Java中的字符串是共享和优化的,因此字符串大小的计算并不是简单的操作。

编辑:
我看到有人提到 LinkedList,请注意,在该列表中总是有额外的指针变量也需要存储在内存中。

You're using ArrayList. So it is a list based on array. There is no way to change size of array without create new, bigger one. New array need to be allocated and all elements need to be copied to the bigger one (with some empty space to make adding some amount of elements not so heavy). Try to use String[] table with specified amount of elements to minimize size of it in memory and avoid array copy.

And I'm not sure but I think that in Java, characters in strings are always 16-bit?

And Strings in Java are shared and optimized, so calculation of size of String are not trivial operation.

Edit:
I see that someone mention about LinkedList, be aware that in that list there are always additional pointer variables that also need to be stored in memory.

浅笑依然 2025-01-10 17:08:26

正如其他人在某些时候指出的那样,即使文件大小很小,您也可能需要额外的内存来复制数组列表。

为了获得更好的图像,您可以尝试找出文件大小每增加 10 MB 需要多少额外内存。一定数量的内存将是恒定的,并且无论文件大小如何都需要。

其次,您还应该在执行完整 GC 后测量内存。您可以使用 JVisualVm 查看内存被占用的位置。

As pointed out by others at some point even if the file size is small you may need extra memory for copying the array list around.

For better picture you can try to find how much extra memory is required for say every 10 MB increase in file size. Some amount of memory is going to be constant and is needed irrespective of file size.

Secondly you should also measure the memory after doing full GC. you can see where memory is being taken up using JVisualVm.

无人接听 2025-01-10 17:08:26

ArrayList的默认容量是10,之后它的容量加倍,所以如果你有100 000个元素,实际分配的容量可以是200 000,这可能是这个异常的原因

Default capacity of ArrayList is 10, after that its capacity is doubled, so if you have 100 000 elements the real allocated capacity can be 200 000, that could be the reason for this exception

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文