【问题标题】:Memory problems with frequent Integer.toString() conversions频繁 Integer.toString() 转换的内存问题
【发布时间】:2013-03-02 17:03:58
【问题描述】:

我目前正在将使用 C#(适用于 Windows Phone)开发的游戏移植到 Java (Android)。

我们在 Java 版本中遇到了内存问题,经过分析,这似乎来自内存中的大量 String 对象,这显然是由于 String 的不可变性质。现在,我设法将其追溯到将玩家的分数呈现到屏幕上的方法,每次分数变化时(每秒多次)都会使用Integer.toString()。我不能真正使用 StringBuilder(这是我们在 C# 版本中所拥有的),因为我们使用的框架的文本呈现方法只接受 String 作为参数,因此无论如何都会发生转换。

这是 Java 中的常见问题吗?谁能推荐一个解决方案(除了联系框架开发人员要求他们修改他们的方法!)?

更新:

游戏节奏非常快,分数部分基于从当前“阶段”开始所经过的时间。它每秒更新 15 次。

我们不保留对字符串的引用,但我在想可能是框架泄漏或复制了这些字符串,所以我正在尝试调查(它不是公共框架,据我所知它没有)还没有被用于这种快节奏的游戏)。

池化是一个很好的建议,我想尝试一下,但必须修改评分系统才能获得一组固定的值。

【问题讨论】:

  • 您多久更新一次屏幕上的分数?
  • 你确定 Integer.toString() 是问题吗?除非您以 100 次/秒的速度执行此操作,否则通常不会对性能产生影响
  • 游戏一次显示多少分数。如果内存中有大量 String 对象,而您只需要一两个,这意味着应用程序正在泄漏字符串,而垃圾收集器无法收集它们。检查分析器哪些对象引用了字符串,它可能会给你一个线索。
  • 可能是内存泄漏导致对这些字符串的引用。

标签: java android string performance


【解决方案1】:

我不确定它是否对您的特定情况有所帮助,但一般来说,当您使用一些 固定集 字符串值进行操作时,添加所有这些值是有意义的到字符串池。在这种情况下,您可以强制 JVM 不在堆上为每个新字符串创建对象,而是使用字符串池。

您必须更改代码以从池中返回字符串,例如:

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

来自 javadoc 的一些额外解释:

当调用 intern 方法时,如果池中已经包含一个等于该 String 对象的字符串,由 equals(Object) 方法确定,则返回池中的字符串。否则,将此 String 对象添加到池中并返回对该 String 对象的引用。

【讨论】:

  • 这是一个很好的建议,但如果分数每次都更改为新值,它可能不适用于这种情况。
  • @iTech 你是对的。从这个问题中并不清楚分数集是否固定,坦率地说,如果没有一些分析信息,很难说问题是什么。
【解决方案2】:

我们最终解决了这个问题,方法是创建我们自己的由固定长度 char 数组支持的可修改字符串类,并编写我们自己的文本渲染方法,一旦初始化就实现零分配。

在此之后,一切都运行得更加顺利,但我们仍然有一些由 GC 引起的“冻结”。分析后发现这是由于在主游戏循环期间在循环中创建了大量迭代器。然后我们编写了一个使用迭代器池的自定义数组类,现在一切运行良好!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-03
    • 1970-01-01
    • 2021-01-04
    • 2019-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-28
    相关资源
    最近更新 更多