2

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

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

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

我遇到的问题是,当我存储n=114(这恰好是我的测试数据中的数字)Pair对象时,Foo它的保留大小应该不超过 228 字节,而实际上它更像是 25kbytes。这意味着当我有大约 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实例。

4

5 回答 5

3

我不完全确定我的问题是否正确,但在这种情况下使用 Flyweights 可能会奏效。

蝇量级模式

于 2012-08-07T10:47:38.643 回答
0

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

在 Java 中,字符串中的一个字符需要两个字节来存储。因此,与将文件保存在驱动器上相比,您至少可以期望将内存使用量翻倍。

每个对象,每个小字符串都需要一个字的信息,因为 JVM 需要指向您的对象的指针。因此,每对数据都是一个单词表示键,一个单词表示值加上每个数据的实际大小。现在这些指针被添加到散列中,散列使用一个词指向自身,并使用几个词指向条目集。就这样。这是面向对象的编程。

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

于 2012-08-07T10:51:08.833 回答
0

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

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

于 2012-08-07T10:51:45.307 回答
0

你说:

我有一个应用程序,它从文件中获取数据并将其存储以供以后使用

后来(在评论中)

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

我怀疑您最节省内存的解决方案是存储文件并根据请求对其进行解析,而不是提前解析和存储。但是您真的要这样做并承受相关的性能成本吗?我不认为你的记忆问题特别大,但是(正如其他人所说)我会调查flyweight 模式

于 2012-08-07T10:58:36.463 回答
0

看看这里。您会发现在 JVM 堆中存储类(字符串或其他)所需的字节数比您想象的要多得多。

1 个字符串的 36 个字节听起来很正确,因为您需要为包含该字符的对象存储大量元数据(请务必考虑 UTF 编码)以及字符串类开销。

于 2012-08-07T11:00:21.900 回答