2014-11-01 33 views
1

我的问题是关于JVM 1.8中匿名对象的处理和生命周期。Lambda表达式匿名对象生命周期

就我所知,在JDK 1.8中,lambda表达式的基本机制不是纯粹基于函数的。即它仍然使用我们在代码中定义的方法创建一个匿名对象,并根据匿名对象调用该方法。另外,因为lambda表达式不会引入任何新的变量作用域,所以在lambda表达式中调用“this”将引用原始对象而不是这种匿名方法。

自然,问题如下:JVM如何处理这种匿名对象的生命周期?定义包含这种lambda表达式的对象方法为“外部对象方法”,至少我有以下问题。

  1. 如果外部对象方法是普通方法,那么这个匿名对象是属于实例级别还是类级别?如果外部方法是静态的呢?

  2. 如果外部对象方法被多次调用,这个匿名对象会被重新使用还是重新创建?

  3. 这样的对象是否受JVM GC支配?如果是,则GC规则与其他对象保持相同?

  4. 有没有任何工具或API来跟踪这种匿名对象的生命周期,因为它不能直接在代码中被引用?

赞赏任何帮助或评论或文件。

+1

1)和2)或多或少地取决于JVM的实现,尽管HotSpot对于这些事情非常聪明。 3)是的,正常。 4)你可以正常地追踪它;如果您愿意,您可以直接将其分配给功能接口类型并进行正常跟踪。 – 2014-11-01 08:22:33

+0

谢谢。如果我们有一些正式的文档,那会很好。对于传递对象肯定是可追踪的;但是我想知道如果嵌入这样的对象的实现。它可能应该是相同的机制,但你知道,有时候有例外。 – 2014-11-03 01:44:28

+0

我有一个关于这个匿名对象的生命周期的类似问题,如果我把一个循环创建lambda表达式,Java运行时将创建这个匿名对象的多个实例。 – apersiankite 2017-01-12 13:11:19

回答

0
  1. 我不知道你是什么意思的“属于”。一个对象不属于任何级别。

  2. 如果拉姆达是封闭的,即,如果它捕获来自周围范围的一个或多个局部变量(包括this(这是有点像一个隐含final局部变量),OuterClass.this(其隐含地通过隐藏字段访问或者非限定实例变量(通过thisOuterClass.this隐式访问)),那么在不同时间对包含lambda表达式的函数进行评估,它可能必须创建不同的对象,因为捕获的变量的值是作为lambda对象的一部分存储,并且由于在函数的不同运行中(或者甚至在函数的一次运行中的不同时间内),捕获的变量可以具有不同的值,不同的必须创建ent lambda对象,以便每个lambda都能记住其单独的一组捕获值。

    但是,如果lambda不是闭包,那么从该lambda表达式创建的任何两个lambda对象在语义上都是不可区分的。那么一个对象可以重新用于该lambda表达式的所有评估。我相信在这种情况下,虚拟机会为该程序的持续时间内生存的lambda表达式静态分配一个对象。

  3. 是的。如果运行lambda表达式时创建了一个对象,那么它将像Java中的其他对象一样动态分配,并且受GC支配。但是,如果一个对象是在程序的整个生命周期中创建的(参见上面(2)的讨论),那么它将不会被内存管理,类似于字符串文字。

+0

谢谢,但你的答案只是猜测。如果您有任何官方文档来确认JVM的行为,或者至少是Oracle JVM,那很好。当然,JVM“可以”重复使用它并“可以”GC这样的匿名对象;但是我问,如果它“确实”重复使用或GC化它们。 – 2014-11-05 10:06:25