如何处理Java中许多小对象的内存效率

时间:2012-08-07 10:42:25

标签: java oop memory

我有一个应用程序从文件中获取数据并存储它以供以后使用。文件中的每一行对应一个对象Foo,其中包含nBar个对象,这些对象由单个字符String组成,每个对象都有一个不同的Name }}。所以我存储这样的数据:

Foo extends HashMap<Name, Pair<Bar, Bar>>

其中Pair<A, B>是我自己的类,它只存储2个值并提供一些方法(equalshashcode等。)

我遇到的问题是,当我存储n=114(这恰好是我的测试数据中的数字)Pair Foo对象时,它应该有一个保留的大小不超过228字节,实际上它更像是25千字节。这意味着当我有~1000 Foo个对象时,我需要25MB内存而不是228kB,这是不可接受的。 (注意:每个Foo对象的键都相同,fooOne.keySet().equals(fooTwo.keySet())

我正在使用VisualVM来分析我的应用程序,当我深入研究Foo的实例时,我看到了:

Field           Type             Retained
-               
this            Foo              24750
...             
v table         HashMap$Entry[]  24662
  v [0]         HashMap$Entry    200
    v value     Pair             156
      v first   Bar              60
        ...
        > code  String           36
      v second  Bar              60
        ...
        > code  String           36
    v key       Name             72
      ...
      > name    String           36
  > [1]         HashMap$Entry    200
  > [2]        <HashMap$Entry>   -
  ...
  > [233]       HashMap$Entry    600
  ...
  > [255]      <HashMap$Entry>   -

因为你可以看到所有有用的信息被许多无用的(对我来说)数据所包围。如果我拥有更少,更大的具有相同数据的对象,我可以看到我的用处:无用的比例会更好,但我看不出如何以任何其他方式实现这一点。还有其他方法可以存储我的数据,但仍然像这样方便易用吗?

修改

我的应用程序需要可扩展到6000个Bar个实例,可能还有Foo个实例。

5 个答案:

答案 0 :(得分:3)

我不完全确定我的问题是对的,但在这种情况下使用Flyweights可能会有所帮助。

Flyweight pattern

答案 1 :(得分:0)

我认为你的很多问题一般只是面向对象的代码,特别是Unicode转换。

在Java中,字符串中的字符需要存储两个字节。因此,至少可以将内存使用量增加一倍,而不是将文件保留在驱动器上。

每个对象,每个小字符串都需要一个有关信息的单词,因为JVM需要指向您的对象的指针。因此,每对数据都是键的一个词,值的一个词加上每个的实际大小。现在这些指针被添加到哈希中,哈希使用一个单词指向自身,并且几个单词指向入口集。它就这样了。这是面向对象的编程。

现在您可以更改代码以将对存储为简单的char [2]。这会减少你的记忆足迹。然后,当您想要与它进行交互时,可以使用Pair对象包装数组。

答案 2 :(得分:0)

您可以尝试删除Bar和Pair对象并存储一对简单的String对象,例如。 “ab”(其中“a”,“b”当前对应于由Bar(“a”)和Bar(“b”)组成的对)

可能使用Flyweight模式来共享所有Foo对象的常用名称,因为您有fooOne.keySet().equals(fooTwo.keySet())

答案 3 :(得分:0)

你说:

  

我有一个应用程序从文件中获取数据并存储它   稍后使用

以及稍后(在评论中)

  

我被要求尽可能提高内存效率

我怀疑你最有效的内存解决方案是存储文件并根据请求解析它,而不是提前解析和存储。但是你真的想这样做并遭受相关的性能成本吗?我不认为你的记忆问题特别严重,但(正如其他人所说)我会调查flyweight pattern

答案 4 :(得分:0)

看看here。你会发现你需要比你想象的更多的字节来存储一个类(字符串或其他)在JVM的堆中。

一个字符串的36个字节听起来非常正确,因为您需要为保存该字符的对象存储大量元数据(确保考虑UTF编码)以及字符串类开销。