0

I have doubt about interfaces and memory leaks, considering the block of code below, could it bring to a memory leak? If so what's the best solution or alternative?

public class MyClass {
    public interface MyClassListener{
         doStuff();
    }

    public doSomething(){}
}

public class OtherClass {

    private List<MyClass> list = new ArrayList<MyClass>();
    private boolean doingStuff = false;

    public void setListener(MyClassListener list) { //Sets the listener}

    public MyClass.MyClassListener listener = new MyClass.MyClassListener() {
        public void doStuff(){ doingStuff = true; }
    }

    public void addMyClass(MyClass obj) {
        obj.setListener(listener);
        list.add(obj);
    }

    public void doSomethingInMyClass(int index) {
        ....update some stuff....
        list.get(index).doSomething();
    }
}

i know i could declare the variable listener as static so it wont hold a reference to OtherClass and assign that reference to a WeakReference but am i going to a memory leak anyway? Since the reference will hold a reference to an object containing a list which contains my object. It is like a chain.

Update

I updated my question, as you can see MyClass has a method called doSomething(), instead OtherClass has a method called doSomethingInMyClass which calls the doSomething method but updates some parameters. What i want is to avoid to use doSomethingInMyClass and get notified of the changes anyway.

MineConsulting SRL
  • 2,340
  • 2
  • 17
  • 32
  • 2
    This is what's called an island of self-referencing objects. Java's garbage collection is able to remove those when the last reference from outside the island is gone. – BeyelerStudios Oct 02 '15 at 12:47
  • It means it will remove the `OtherClass` object when the list will be empty? – MineConsulting SRL Oct 02 '15 at 12:50
  • Yes. Java Garbage Collection starts with the _active threads'_ local variables, plus the _static_ members of all loaded classes. Those are the first-level living objects. Then GC recursively marks all objects that are referred from these living objects. The rest (unreferences objects) are removed from the heap after the GC. – gaborsch Oct 02 '15 at 13:35
  • Have a look at this question: http://stackoverflow.com/questions/407855/how-does-java-garbage-collector-handle-self-reference – gaborsch Oct 02 '15 at 13:41
  • Please see my update, i don't want to know how it is garbage collected. – MineConsulting SRL Oct 02 '15 at 14:03

1 Answers1

0

Here's an example of your situation:

interface I { }

class A {
    List<I> list = new ArrayList<>();
    void add(I item) { list.add(item); }
}

class B {
    A other;
    void setA(A a) {
        final B self = this;
        a.add(new I() { B owner = self; });
        other = a;
    }
}

[...]

public static void main (String[] args)
{                   // 1
    A a = new A();  // 2
    B b = new B();  // 3
    b.setA(a);      // 4
}                   // 5

At the start of the scope in main the set of references is empty in (1). a and b are set to reference each other in (4). Then the references to a and b are removed at the end of the scope in (5). The result is an island of self-referencing objects.

You can visualise the set of (non-null) references as follows:

  1. {}
  2. {a, a.list}
  3. {a, a.list, b}
  4. {a, a.list, a.list[0], a.list[0].owner, b, b.other}
  5. {a.list, a.list[0], a.list[0].owner, b.other}

In the end you have a reference to a list in a, it contains one or multiple references to the internal I in B which contains a reference to its owner b, wich contains a reference to a. When the garbage collector adds up the reference counts per object from this list it can remove them all if those counts are equal to the actual reference counts (i.e. the list is completely self-referential).

BeyelerStudios
  • 4,243
  • 19
  • 38