A memory leak in Java, but not in Kotlin (the same code base) ... why?

I have a piece of simple code below in action ...

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

            }
        });
        valueAnimator.start();
    }
}

If the action stops, a memory leak will occur (as proven by Leak Canary).

However, when I hide this code until the identical Kotlin code (using shift-alt-command-k), it is as below

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
        valueAnimator.repeatCount = ValueAnimator.INFINITE
        valueAnimator.addUpdateListener { }
        valueAnimator.start()
    }
}

A memory leak no longer occurs. What for? Is it because an anonymous class object is converted to Lambda?

+6
source share
3 answers

The difference between the two versions is quite simple.

Java- AnimatorUpdateListener (MainActivity ). , , , , .

. , , ValueAnimator, (.. MainActivity), AnimatorUpdateListener, . .

:, - , Kotlin , , [re] MainActivity ( (), ).

: "Kotlin in Action", Kotlin , Kotlin , SAM .

+6

1. ,

, , "Show Kotlin Bytecode" , , . . InteliJ. ( , )

2. JVM , Kotlin

Kotlin JVM Java ( , Java), ​​ . , , . :

Java, , , .

  • noinline, ,
    .
  • , , ( + ).
  • lambda , , .

: http://openjdk.java.net/jeps/8158765

3.

, , : fooobar.com/questions/844784/... , , , , - ,

+1

, addUpdateListener .

. JavaAbstract foo:

public interface JavaInterface {
     void foo();
}

JavaInterfaceClient:

public class JavaInterfaceClient {
    public void useInterfaceInstance(JavaAbstract inst){
        inst.foo();
    }
}

, useInterfaceInstance Kotlin:

, , (SAM Conversion):

JavaInterfaceClient().useInterfaceInstance {}

-, Java:

(new JavaInterfaceClient()).useInterfaceInstance((JavaInterface)null.INSTANCE);

, , .

, :

JavaInterfaceClient().useInterfaceInstance(object : JavaInterface {
    override fun foo() {

    }
})

-, Java:

(new JavaInterfaceClient()).useInterfaceInstance((JavaInterface)(new JavaInterface() {
     public void foo() {
     }
 }));

, SAM/lambda. .

+1

All Articles