我有一个应用程序从文件中获取数据并存储它以供以后使用。文件中的每一行对应一个对象Foo
,其中包含n
对Bar
个对象,这些对象由单个字符String
组成,每个对象都有一个不同的Name
}}。所以我存储这样的数据:
Foo extends HashMap<Name, Pair<Bar, Bar>>
其中Pair<A, B>
是我自己的类,它只存储2个值并提供一些方法(equals
,hashcode
等。)
我遇到的问题是,当我存储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
个实例。
答案 0 :(得分:3)
我不完全确定我的问题是对的,但在这种情况下使用Flyweights可能会有所帮助。
答案 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编码)以及字符串类开销。