【问题标题】:Minimizing Garbage Collection in Java Attempt (with example)在 Java 尝试中最小化垃圾收集(带有示例)
【发布时间】:2013-07-21 04:23:47
【问题描述】:

q(除此之外 - 我不确定对于已创建但未存储在变量中的对象该术语是什么)。

我真的不知道如何很好地表达我的问题,所以我将说明它。

示例一,声明了两个对象:

Random random = new Random();
for (int i = 0; i < 10000000; i += 1){
    Integer integer = new Integer(random.nextInt());
    String string = integer.toString();
}

仅声明一个对象的示例二:

Random random = new Random();
for (int i = 0; i < 10000000; i += 1){
    String string = (new Integer(random.nextInt())).toString();
}

在第二个例子中,仍然创建了 Integer 对象,但它在内存中的位置没有保存(我认为)。我知道将对象创建减少一个似乎微不足道,但是在具有许多迭代的大循环中,将对象引用减半肯定是有益的。这种技术是否可以节省内存(即最小化垃圾收集)?

编辑:更改了示例以更好地说明问题。

【问题讨论】:

  • 可能你想展示一个比这更好的例子。
  • 这两种情况都会创建完全相同数量/类型的对象。为了内存使用,局部变量在这里是无关紧要的。此外,使用 Integer.valueOf(5) 会“更好”,因为它通常会使用缓存并完全避免创建新的 Integer 对象(关于这个主题有很多 SO 问题)。
  • 虽然这里有一个 subtle 问题,因为局部变量是 GC 根(尽管对于有问题的小型不可变 Integer 类型来说,这非常没有实际意义) ,如果这些变量出现在循环中,则这是无关完全相同数量/类型的对象被创建;变量和额外的赋值都没有“添加”新对象。
  • 这里的简单解决方案是完全避免创建 Integer,您不需要它。然后,您可以消除创建字符串的需要(取决于您使用的内容),并且您根本不会创建任何垃圾。

标签: java object memory


【解决方案1】:

这种技术是否可以节省内存(即最小化垃圾收集)?

事实上,你问的是两个不同的问题。答案是“否(在实践中)”和“否”。

(这适用于问题的原始版本和更新版本。)


第一个答案需要一点解释。

在第一个例子中,如果这是在一个循环中,那么stringinteger 变量要么会多次超出范围,要么会被多次覆盖。 (在您的示例中,它们超出了范围。)

如果其中任何一种发生,变量的当前值将被“遗忘”,相应的对象将变得无法访问。

在第二个示例中,您没有将Integer 对象放入变量中,因此相应的对象可能会在几纳秒前变得无法访问。但由于这段代码在循环中,所以差异可以忽略不计。事实上,它可能是无法衡量的。


第二个答案更容易解释。如果两个分配之一(即创建Integernew 语句或创建Integer.toString() 的内部Integer.toString())之一需要,您的代码只会触发垃圾收集比立即可用的内存更多。由于两段代码执行相同的分配,因此 GC 将运行的 次数没有差异。


另一点是,在 Java 中以这种详细程度考虑这些事情只是浪费时间。一般来说,垃圾收集器只负责处理事情。在这个特定示例中,“优化”的最大理论优势是单个Integer 对象可能会在垃圾回收周期更早的时候被释放。该对象占用大约 16 个字节。这根本不值得考虑。

您正在做的事情在业内被称为“过早优化”。不要在上面浪费时间。如果你需要优化,等到你有一个工作程序,然后分析它。然后把精力花在分析器认为有问题的部分上。

【讨论】:

    【解决方案2】:

    无论它是两种方法之一,在这两种方法中都有在单次迭代范围内创建的两个对象。一旦迭代完成,两者都有资格获得gc

    现在,IMO GC minor cycle(在这种短期对象的特定情况下)不会每次迭代,并且会在相关空间充满 GCed 对象时发生(检查 jstat -gcutil),没关系您选择哪种方法,因为两者都会为您提供相似的内存统计信息。

    【讨论】:

      【解决方案3】:

      这是一个过早的优化,您可能永远不需要这样做。

      但是,是的。只要integer 永远不会超出范围,就永远不会被垃圾回收。

      【讨论】:

        【解决方案4】:

        可达的对象将有资格进行垃圾收集(在您的情况下为new Integer(5)

        请参阅Tuning Garbage Collection,但我怀疑您是否需要这样做

        【讨论】:

        • 我总是对 Java 的处理方式感到好奇:void f() { X x = new X(); while(forALongTime) { .. }; },但似乎从未完全关注过它。 x 可以在函数存在之前 被回收吗?它可以在 C#/CLR 中。根据我对 Java 中可达性根源的理解,相同的“早期”回收是不可能的……但这能保证吗?无论如何,可以访问的整数并不令人兴奋:D
        • integer 可达的。
        • @user2246674 没有。xwhile 循环中是可达的,所以它不能被回收。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-12-13
        • 2017-04-07
        • 2018-06-10
        • 2013-04-20
        • 1970-01-01
        • 2011-02-25
        相关资源
        最近更新 更多