我正在致力于将 Roguelike 地下城冒险游戏移植到 Android 上。
http://tyrant.sourceforge.net
当我启动程序时,我首先初始化世界及其所有对象。我有一个包含 300 万(!)HashMap 条目的类。当我尝试初始化该类时,在我的 Android 上运行需要 5 分钟以上,这是一个非常不可接受的时间长度。一旦类被初始化,游戏就运行良好并且非常有趣。
所以我想我可以序列化这个对象并在运行时重新加载它。我将它序列化,并将其打包到.APK 文件中,它的大小超过5MB。 Android 只是卡住并给我一个 OutOfMemory 错误。
我可以反序列化该类的一部分(800KB),然后动态创建其余条目。这仍然需要相当长的时间才能完成,它仍然需要从序列化数据创建 300 万个条目。但我确实知道我的序列化代码工作正常。
如何在 Android 上存储这个非常大的类文件并稍后加载它?我可以探索哪些选项?让我的用户等待 5 分钟才能启动应用程序根本不是很好。
这是原始源代码中令人不安的类:
http://tyrant.cvs.sourceforge .net/viewvc/tyrant/tyrant/mikera/engine/Lib.java?view=markup
令人不安的字段是:(
private transient Map types;
我知道它是暂时的)
它最终存储在300万条参赛作品!
I am working on porting a Roguelike dungeon adventure game to the Android.
http://tyrant.sourceforge.net
When I start my program, I initialize the world and all it's objects first. I have a class that contains 3 million(!) HashMap entries. When I try to initialize that class, it takes 5+ minutes to run on my Android, which is a very unacceptable length of time. Once the class is is initialized, the game runs great and is quite fun.
So I thought I could serialize this object and reload it at runtime. I serialize it, and pack it in the .APK file, it's over 5MB in size. Android just chokes and gives me an OutOfMemory error.
I can deserialize part of the class(800KB), and then dynamically create the rest of entries. That still takes quite a few minutes to finish too, it still has to create 3 million entries from the serialized data. But I do know that my serialization code works fine.
How can I store this very large class file on the Android and load it later? What are some options I can explore? Making my user wait 5 minutes for the app to start is not very good at all.
Here is the troubling class in the original source code:
http://tyrant.cvs.sourceforge.net/viewvc/tyrant/tyrant/mikera/engine/Lib.java?view=markup
and the troubling field is:
private transient Map types;
(I'm aware it's transient)
it ends up storing over 3 million entries!
发布评论
评论(3)
问题的一部分在于
types
映射中的内容。据我所知,它实际上是一个
Map>
,其中第二级映射实际上是非稀疏数组。如果您选择更好的数据结构,它将占用更少的空间,并且您可以更快地构建它。 (我认为你不序列化它是对的......因为它看起来在游戏过程中可能不会改变。)HashMap
比占用更多的空间>对象[]
。更好的数据结构是
Map
其中LevelMap
是这样的:Well part of the problem is what is in the
types
map.From what I can make out, it is effectively a
Map<String, Map<Integer, List>>
, where the 2nd level maps are really non-sparse arrays. If you chose a better data structure it would occupy less space and you could build it much faster. (I think you are right not to serialize it ... since it looks like it might not be changed during game play.)A
HashMap<Integer, Object>
takes a LOT more space than anObject[]
.A better data structure would be
Map<String, LevelMap>
whereLevelMap
is something like this:我认为你的部分问题是你的条目太厚了。查看您的代码,您是否为每个事物存储了一个字符串键控属性的 HashMap?那可能会杀死你。首先要做的就是切换到基于枚举的 HashMap,看看这是否会带来性能差异 [并且 sum 适用于所有地方的所有字符串 - 将它们替换为到处的枚举,并使用将它们转换为字符串的实用程序(如果它们)需要向用户显示]
现在,为什么你有 300 万个条目?!?!这就是你的整个世界吗?如果是这样,你能把它分成 100 个棋盘格,写入 100 个不同的文件,然后开始只加载你的英雄所在的格子,然后在后台加载其余的格子吗?
I think part of your problem is that your entries are too fat. Looking over your code, you store a HashMap of String-keyed properties for every Thing? That's probably killing you right there. First thing to do is switch to enum-based HashMap, and see if that makes a performance difference [and sum applies to all your Strings all over the place - replace them with enums everywhere, and have on utility that converts them to Strings if they need be displayed to users]
Now, why exactly do you have 3 million entries?!?! is that your entire world? If so, can you break it up into 100 squares ala chessboard, write out into 100 different files, and start off only loading the square your heroes are in, while loading the rest in the background later?