Should I clean my circular reference?

Former Member
Former Member
Is this really a valid circular reference? I thought not, because Child.mCallback cannot exist without Parent, but simulator says it is. It seems you cannot invoke a weak reference, so using callback.weak() & mCallback.get().invoke("data") will not work. I can clean it up with the lines in MyApp.onStop(state). What I what to know is should I bother with said cleanup?

var globalParent;

class MyApp extends App.AppBase {
function initialize() {
globalParent = new Parent();
globalParent.child.doTask();
}

function onStop(state) {
// Should I bother with this code?
globalParent.child = null;
}
}

class Parent {
var child = new Child(method(:onChild));

function onChild(data) {
// do something with stuff
}
}

class Child {
hidden var mCallback;

function initialize(callback) {
mCallback = callback;
}

function doTask() {
mCallback.invoke("stuff");
}
}
  • Former Member
    Former Member over 8 years ago
    I think you may not be understanding what happens with a circular reference.

    In your case, you have a Parent class, which references its Child, which references a Lang.Method object, which references the Parent. This creates a circular reference, but to begin with, these are not the only references. Your app has an additional reference to Parent from AppBase, which is your App's access point to the object.

    In a normal case, with no circular reference, you will have something like this:

    AppBase -> Parent (ref count 1) -> Child (ref count 1)

    When the AppBase is destroyed at the end of your app (the reference to it held by the VM is removed and its ref count reaches 0), each variable contained by AppBase will be decremented. One of these is the Parent class. This causes the Parent count to reach 0, which triggers its destruction, and decrements its child, which will also reaches 0, and is destroyed.

    In your example, we have a circular reference and the reference tree looks like this:

    AppBase -> Parent (ref count 2) -> Child (ref count 1) -> Lang.Method (ref count 1) -> (Back to Parent)

    When the AppBase is destroyed at the end of your app, the Parent object is decremented, but the reference count does not reach 0, and it is not destroyed. You now have a chain of orphaned memory that does not have any external references, and cannot be recovered.

    Parent (ref count 1) -> Child (ref count 1) -> Lang.Method (ref count 1) -> (Back to Parent)


    Here is a simple example that will leak memory in an app:

    function leaky() {
    var a = new [1]; //Array of size 1 referenced on the stack
    var b = new [1]; //Array of size 1 referenced on the stack
    a[0] = b; //Array b now referenced by a[0]
    b[0] = a; //Array a now referenced by b[0]
    } //Stack references are decremented, but circular reference remains. Data is not cleaned up, but can no longer be accessed.
  • Former Member
    Former Member over 8 years ago
    Yes I didn't fully understand it at the start. I thought it was Child that was holding the reference to Parent. Travis explained how that wasn't the case.


    I will leave it in despite the fact the reference would only be left if the app is somehow shut down unprogrammatically mid execution. It would be better to not return any errors.


    Thanks for all the responses.