在此示例中,有多少对象符合垃圾收集器的条件

时间:2016-07-12 01:25:57

标签: java garbage-collection

public class Currency {
    String name = new String();
    static Integer value = new Integer();
    static void getCurrency(Integer v) {
        Currency c = new Currency();
        c.value = v;
    }
    public static void m() {
        Currency.getCurrency(50);
        Currency.getCurrency(100);
    }
    public static void main(String[] argv) {
        Currency.m();
    }
}

m()退出时,我会计算5个符合垃圾收集器条件的元素。练习说6是正确的答案。你能救我吗?

2 个答案:

答案 0 :(得分:1)

getCurrency()进行的两次调用将分别创建两个 Currency个对象。每次通话都需要:

  • Integer对象作为参数,稍后分配给value
  • 一个Currency对象
  • 一个name字符串对象(不是static,即每个Currency对象都有一个)

3×2 = 6

<强>更新

最大的问题似乎是,是否会为每次调用Integer构造函数创建一个新的Currency对象。将原始int自动装箱到Integer会调用Integer.valueOf()Javadoc可以说Integer.valueOf()

  

返回表示指定int值的Integer实例。如果不需要新的Integer实例,通常应优先使用此方法,而不是构造函数Integer(int),因为此方法可能通过缓存频繁请求的值来显着提高空间和时间性能。 此方法将始终缓存-128到127(包括-128到127)范围内的值,并可以缓存此范围之外的其他值。

因此缓存了-128到127范围内的值。但问题是,在您的代码中,您正在使用两个不同的值,50和100,因此缓存不会避免创建新的Integer对象AFAIK。

答案 1 :(得分:0)

我不同意接受的答案。我相信你对五个物品有资格进行垃圾收集的回答实际上是正确的,而你正在进行的练习是错误的(虽然如果有人能解释我是怎么弄错的,我会非常感激它。) / p>

以下是程序引用的对象:

  1. Integer#0 - 由Integer *
  2. 创建的static Integer value = new Integer()
  3. Currency#1 - 由Currency创建的Currency.getCurrency(50)
  4. Integer#1 - Integer自动装箱返回的50
  5. String#1 - StringString name = new String()#1创建时创建的Currency
  6. Currency#2 - 由Currency创建的Currency.getCurrency(100)
  7. Integer#2 - Integer自动装箱返回的100
  8. String#2 - StringString name = new String()#2创建时创建的Currency
  9. *这实际上并没有编译,但我认为它已经被有效的代码所取代,而这些代码对程序没有任何影响。

    因此,您的代码需要七个对象才能运行。当valuevalue覆盖时,50最初引用的对象有资格进行垃圾回收。当Currency的唯一引用超出范围时,第一个和第二个m符合条件。第一个和第二个String符合条件m,当他们唯一的引用对象Currency s 1和2超出范围时。来自Integer的自动装箱100最后仍被静态参考value引用,因此不符合垃圾回收条件。这5个对象符合条件,1个不合格,还有1个尚未讨论。

    最后一个对象是Integer自动装箱返回的50。您的代码显然不再引用它,因为value设置为引用100。这似乎表明它有资格进行垃圾收集,但我不同意。 Integeris know to cache values at least in the range -128 to 127以符合JLS 5.1.7。因此,当m退出时,缓存仍会包含对来自Integer的装箱50的引用,导致它不符合垃圾回收的条件。

    我尝试使用此程序测试此行为:

    public class Test{
        public static final WeakReference<Integer> inCache = new WeakReference<>(50);
        public static final WeakReference<Integer> outOfCache = new WeakReference<>(10000);
        public static void main(String[] args){
            System.gc();
            System.out.println(inCache.get());
            System.out.println(outOfCache.get());
        }
    }
    

    哪个输出

    50
    null
    

    表明,至少在这种情况下,未缓存的Integer被垃圾收集而缓存的50没有收集。这表明,即使没有明确引用System.gc(),由于缓存中存储的引用,它仍然没有资格进行垃圾收集。

    我承认这并不能证明任何事情,因为,Integer并不能保证它会收集所有(或任何)可用内存。但是,我认为这应该表明问题并不像人们想象的那样简单,而且在最常见的JDK / JVM上,第六个值不符合垃圾收集的条件是合理的。

    TL; DR - 我不认为装箱50返回的Integer有资格进行垃圾收集,因为它仍由select * from events where timestamp >= UNIX_TIMESTAMP( 06:00:00 AM) and timestamp < UNIX_TIMESTAMP(05:59:59 AM) 维护的缓存引用类。