简体   繁体   English

频繁的Integer.toString()转换导致的内存问题

[英]Memory problems with frequent Integer.toString() conversions

I'm currently in the process of porting a game developed in C# (for Windows Phone) to Java (Android). 我目前正在将用C#开发的游戏(用于Windows Phone)移植到Java(Android)。

We're having memory issues in the Java version which, after profiling, seem to be coming from a huge number of String objects in memory, evidently due to the immutable nature of String 's. 我们遇到的Java版本内存问题其中,剖析后,似乎是从一个巨大的数字未来的String内存中的对象,显然是由于不可变的性质String的。 Now, I've managed to trace this down to the method which renders the player's score to the screen, where a Integer.toString() is used every time the score changes (many times per second). 现在,我设法将其追溯到将玩家得分显示在屏幕上的方法,该方法在每次得分改变(每秒多次Integer.toString()使用Integer.toString() )。 I can't really use a StringBuilder (this is what we have in the C# version) because the text rendering methods of the framework we're using only accept String 's as arguments, therefore a conversion occurs anyways. 我不能真正使用StringBuilder (这是C#版本中的功能),因为我们使用的框架的文本呈现方法仅接受String作为参数,因此无论如何都会发生转换。

Is this a common problem in Java? 这是Java中的常见问题吗? Can anyone recommend a solution (aside from contacting the framework devs to ask them to modify their methods!)? 任何人都可以推荐解决方案(除了联系框架开发人员要求他们修改其方法!)?

Update: 更新:

The game is very fast-paced and the score is partly based on the time elapsed since the start of the current "stage". 游戏节奏非常快,得分部分取决于自当前“阶段”开始以来经过的时间。 It's updated 15 times per second. 每秒更新15次。

We don't keep a reference to the string, but I'm thinking maybe the framework is leaking or duplicating these strings so I'm trying to look into that (it's not a public framework and to my knowledge it hasn't been used for this kind of fast-paced game yet). 我们没有保留对字符串的引用,但我认为框架可能正在泄漏或复制这些字符串,因此我试图研究一下(这不是一个公共框架,据我所知尚未使用对于这种快节奏的游戏而言)。

The pooling is a good suggestion and I thought of trying that but the scoring system would have to be modified in order to have a fixed set of values. 合并是一个很好的建议,我想尝试一下,但是必须修改评分系统才能拥有固定的一组值。

I'm not sure if it helps in your particular case, but in general when you have some fixed set of string values that you're operating with, it makes sense to add all of them to string pool. 我不确定这是否对您的特定情况有所帮助,但是通常,当您使用一组固定的字符串值进行操作时,将所有这些值添加到字符串池是有意义的。 In this case, you can force JVM to not create objects on the heap for each new string but rather utilize string pool. 在这种情况下,您可以强制JVM不为每个新字符串在堆上创建对象,而是利用字符串池。

You'll have to change your code to return strings from pool, like so for example: 您必须更改代码以从池中返回字符串,例如:

return String.valueOf(123).intern();

Some additional explanation from javadoc: javadoc的一些其他说明:

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. 调用intern方法时,如果池已经包含等于equals(Object)方法确定的此String对象的字符串,则返回池中的字符串。 Otherwise, this String object is added to the pool and a reference to this String object is returned. 否则,将此String对象添加到池中,并返回对此String对象的引用。

We ended up solving the problem by creating our own modifiable string class backed by a fixed length char array, and writing our own text rendering methods with zero allocation once initialized. 最后,我们通过创建由固定长度char数组支持的可修改字符串类来解决该问题,并在初始化后编写了零分配的文本呈现方法。

After this, everything ran much more smoothly but we still had a few "freezes" caused by GC. 此后,一切运行得更加顺利,但是我们仍然有一些由GC引起的“冻结”。 After profiling, it turned out this was due to the large amount of iterators created in loops during the main game loop. 经过分析后,发现这是由于在主游戏循环中在循环中创建了大量迭代器所致。 We then wrote a custom array class which uses a pool of iterators, and now everything runs great! 然后,我们编写了一个使用迭代器池的自定义数组类,现在一切运行良好!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM