【问题标题】:Java input = "" isn't the same as input = null?Java input = "" 和 input = null 不一样?
【发布时间】:2010-11-13 20:11:12
【问题描述】:

我正在运行一个 J2ME 应用程序并遇到了一些严重的内存问题。
所以我建立了另一个步骤来清除巨大的输入字符串并处理它的数据并清除它。 但是直到我设置 input = null 而不是 input = "" 才解决问题。

在内存管理方面不应该一样吗?有人可以解释一下区别吗?

谢谢,
雷特

for(int x = 0; x <= ChunksPartCount; x++)
{
    _model.setLoading_bar_progress((x * ChunkSize));
    input += web_service.FullCompanyListChunksGet(x, ChunkSize);

    if((x * ChunkSize) > 5000)
    {
        ReadXML(input);
        input = null;
    }
}

编辑:
我仍然想将答案标记为解决方案。我认为mmyers的言论是朝着正确的方向发展的。

【问题讨论】:

  • 我猜这取决于 J2ME 垃圾收集器的工作方式,但是将 input 重新分配给任何东西(null"""""I like pizza")应该让 GC 回收巨大的输入字符串.
  • 对不起,我不知道答案。当我看到它时,我只知道一个错误的答案。

标签: java memory-management java-me garbage-collection


【解决方案1】:

每个变量实际上都是指向内存中“数据”的指针。

input = "" 将输入分配给字符串对象。它有一个长度 (0) 和一个空数组,以及与之关联的一些其他数据。

input.length() 此时将返回 0。

input = null 使输入指向“无效”。 Null 是一种特殊情况,这意味着该指针指向 NOTHING,它是未分配的。

input.length() 现在会抛出一个异常,因为你什么都没有调用 .length。

【讨论】:

  • 所以 'null' 可能会比 "" 消耗更少的内存,但两者都应该比一些巨大的字符串更好
  • 是的,但每当有人“清空”变量时,我都会有一种非常时髦的感觉。示例中的那个应该是一个方法变量,因此应该在方法退出的第二个消失。将其设置为 null 或 "" 可能只是伤害,因为运行时需要优化。换句话说,如果 input=null 做了上述任何事情,这意味着输入的范围不够好——首先修复它!
【解决方案2】:

使用 StringBuffer 可能是更好的方法

其中一些已在 SO 中得到解答:

String builder and stringbuffer in java

why to use StringBuffer in java instead of the string concantion operator

【讨论】:

  • 这实际上是一个更好的解决方案。
  • 每次你写 input += blah() 时,都会创建一个新的 String 对象,旧的所有内容都会复制到其中,并附加 blah() 的输出,旧的 input 被标记为GC。这是非常缓慢和低效的。 StringBuffer 解决了。
  • 效率不是他的问题。他有一个关于 null 与空字符串的底层实现的问题。所以,你没有回答他的问题。如果他一直在询问性能,那么最好告诉他分析代码的瓶颈。如果他发现了由大量字符串连接引起的问题,那么建议使用 StringBuffer 将是该问题的一个很好的答案。但是,当您不知道他有性能问题,甚至没有问过这个问题时,为什么还要告诉他如何优化呢?
【解决方案3】:

input = null 删除(让垃圾收集器删除)内存中的对象,而input = "" 实例化一个包含空字符串""String 对象。通过将 input 设置为 null,您将 input 设为一个空对象,因此它不会占用 任何 内存,而在设置 input = "" 时,您将其设置为一个新对象,这将肯定会占用一些内存(显然它应该是最小的)。

您可以从 IBM 中查看 this article 谈论 Java GC 和性能,这不利于我之前的建议。它说:

显式归零只是 设置参考对象的实践 完成后为 null 他们。 归零背后的想法是 它通过以下方式协助垃圾收集器 使对象更早无法访问。要么 至少理论上是这样的。

有一种情况是使用 显式归零不仅有帮助, 但实际上是必需的,那就是 对对象的引用在哪里 范围比使用范围更广,或 程序认为有效 规范。 这包括案例 例如使用静态或实例 存储对 a 的引用的字段 临时缓冲区,而不是本地 变量,或使用数组存储 可能仍然可以访问的引用 由运行时而非隐含 程序的语义。

此外,

在 1997 年 9 月的“Java 开发人员连接技术提示”专栏(请参阅参考资料)中,Sun 警告了这种风险,并解释了在像上面的 pop() 示例这样的情况下如何需要显式置空。不幸的是,程序员经常把这个建议走得太远,使用显式空值来帮助垃圾收集器。 但在大多数情况下,它对垃圾收集器没有任何帮助,在某些情况下,它实际上会损害程序的性能。

【讨论】:

  • 但无论哪种方式,旧字符串都没有引用,所以它应该有资格收集。
  • 其中任何一个都会更改输入所指的内容,因此从垃圾收集器的角度来看,它们将具有相同的效果。
  • 你是对的,只要ReadXML和input都不再引用input的原始内容,就应该删除它。但是通过将输入设置为 null,您告诉 GC 尽快删除它。
  • 与任何其他值相比,将引用变量设置为 null 并没有什么特别之处。 GC“尽快删除”绝对不是什么神奇的信号。
  • @voyager 哪里说将变量设置为 null 会告诉 GC“尽快删除它”?我不认为这是真的。
【解决方案4】:

与其推测垃圾收集器为什么不收集你的对象,我更愿意收集有关情况的证据。其他人已经发布了他们的猜测。

如果可能,创建堆转储文件以在 JVM 运行代码时观察它的内存,然后检查它们以查看那里有哪些对象。

这是一个网页,告诉您如何做到这一点: http://twit88.com/blog/2008/12/19/java-troubleshooting-memory-problem/

祝你好运!


另一个想法:编写一个简短的程序,它只会创建大型 String 对象,然后打开详细垃圾收集模式,看看那里会发生什么。如果您可以在一个小程序中重现该行为,那么您可以更轻松地研究它。我想您可能会发现 PC 上的 JVM 可能与手机等 J2ME 设备中的 JVM 行为不同。

【讨论】:

  • 我无法回答这个问题的原因是,我不希望 Java 会这样。 s = null 或 s = "" 之间应该没有区别。 rAyt 表示它确实有所作为,所以我的理解肯定存在差距。通过阅读权威来源(Sun 和 IBM 都不错)和直接实验的信息,我学得最好。
【解决方案5】:

我想补充一点航海家的回答:

关于字符串

从垃圾回收的角度来看,input = ""; 语句与input = "abcde..."; 相同,因为这两个语句都不会使对象实例input 无效,但两者都只是更改了input String 变量的内容。此外,为了精确和清晰,input = something" 更改了input 的内容,而String input = ""; 实例化了input

如果 input == "",那么 'if (input.isEmpty())would be true, butif (input == null)' 将为 false。

关于垃圾回收

语句input = null; 减少此特定对象实例的引用计数,如果它是对input 的最后引用,则input 将被标记为垃圾回收,这将在非确定性AKA 时发生垃圾收集器得到它。 input = null; 实际上不会为垃圾收集标记 input 的情况是:如果 input 也被传递到一个集合中;在从集合中删除 input 之前,它会阻止引用计数递减,因此不会被垃圾回收。

希望这会有所帮助,对于其他任何人,请随时纠正任何错误,即使它们很微妙。

-b

【讨论】:

  • input = "" not “改变 input String 变量的内容”;它只是重新分配它,减少原始字符串的引用计数。从原始大字符串的角度来看,inputany 重新分配会减少引用计数,并且无论重新分配到 ""null 还是"Jon Skeet".
  • 我明白了,你是说input = ""; 并不意味着input 的旧值必须在“标记”阶段进行标记,然后才能在“扫描”中收集" 阶段,而 input = null; 导致它被标记,所以你只需要等待一个 "标记" 阶段?
  • @mmyers 我的印象是 Java 的 GC 没有保留引用计数,因为使用分代 GC 会占用比其价值更多的内存。
  • 重要的是要记住变量是对对象的引用,而不是对象本身。 Java String 对象是不可变的——不可更改。您只能更改变量引用的内容,而不是 String 对象本身。 @imageist 是的,Java 不保留引用计数,它实际上通过在运行时遵循引用图来确定对象是否被任何变量引用。
  • 它不保留引用计数本身,但任何强引用都会阻止 GC 回收对象。
【解决方案6】:

在 Java 中,字符串是对象,而对象变量名总是指针。如果您有一个名为 input 的字符串并且类型 input = null,则它将输入指向内存中的空空间。如果你有 input = "",它会创建一个不包含文本的字符串,一个空字符串。

【讨论】:

    猜你喜欢
    • 2016-07-18
    • 1970-01-01
    • 2013-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-09
    • 1970-01-01
    • 2017-04-09
    相关资源
    最近更新 更多