Complete
over 3 years ago

By design. 

weak() doesn't work or bug in simulator/ActiveMemory

this

code

class Cone
{
	var x;
	
	function initialize(parent)
	{
		x	= parent.weak().get();
	} 
}

class Ctwo
{
	var xs;
	
	function initialize()
	{
		xs = new[2];
		
		xs[0] = new Cone(self);
		xs[1] = new Cone(self);
	}
}

var t = new Ctwo();

in ActiveMemory I can see:

- t Obj #187 Circular Reference!
-- xs Obj #188
--- [0] Obj #189
----x Obj #187 Circular Reference!
...

  •   is right. You seem to be misunderstanding how to use weak references.

    There is a circular reference in exampleOfAccessingX, but it only lasts while the value x is in scope. As soon as x is destroyed, the circular reference is eliminated. This is the entire reason for WeakReference to exist.

    I can simple check null of object. Maybe just for not increment references it has to be special class.

    Your ability to check for null is irrelevant to the problem. In the Ctwo case above, the two Cone instances need references to the parent Ctwo, but the references need to be maintained in such a way that when the Ctwo is no longer needed by the application the two child Cone instances will be cleaned up.

    Consider the memory for the sample code above...

    var t = new Ctwo();
    
    //         +-Ctwo--+
    //         |       |       
    // [ t ]-->|  xs[0]+--------------------*
    //         |  xs[1]+--*   +-Cone--+     |   +-Cone--+
    //         |       |  |   |       |     |   |       |
    //         +-------+  *-->|       |     *-->|       |
    //            ^ ^         |   xRef+--*      |   xRef+--*
    //            | |         |       |  |      |       |  |
    //            | |         +-------+  |      +-------+  |
    //            | *--------------------*                 |
    //            *----------------------------------------*
    
    t = null;

    After the assignment to t, it looks like this..

    //
    // [ t ]--> null
    //
    //         +-Ctwo--+
    //         |       |       
    //         |  xs[0]+--------------------*
    //         |  xs[1]+--*   +-Cone--+     |   +-Cone--+
    //         |       |  |   |       |     |   |       |
    //         +-------+  *-->|       |     *-->|       |
    //            ^ ^         |   xRef+--*      |   xRef+--*
    //            | |         |       |  |      |       |  |
    //            | |         +-------+  |      +-------+  |
    //            | *--------------------*                 |
    //            *----------------------------------------*
    //

    Notice that the Ctwo instance is floating out there in memory? There are no references to it in your application code, so that memory is now 'leaked' in that you have no way to deallocate it. The Ctwo object has strong references to two Cone instances, and each Cone has a strong reference to the Ctwo. They are stuck this way until your app exits and all of the app memory is released.

    One way to avoid this is to break the cycle just before you give up the last reference to the Ctwo object like this...

    t.xs[0].xRef = null;
    t.xs[1].xRef = null;
    
    //         +-Ctwo--+
    //         |       |       
    // [ t ]-->|  xs[0]+--------------------*
    //         |  xs[1]+--*   +-Cone--+     |   +-Cone--+
    //         |       |  |   |       |     |   |       |
    //         +-------+  *-->|       |     *-->|       |
    //                        |   xRef+--> null |   xRef+--> null
    //                        |       |         |       |
    //                        +-------+         +-------+
    
    t = null;
    
    //
    // [ t ]--> null
    //

    The other way to fix this is to avoid the problem in the first place. If you make the xRef references weak, then the Cones will not have strong references back to the parent... as soon as the last reference to Ctwo is nulled, the entire object hierarchy will be deallocated.

    Your argument is that you still have a circular reference while x (inside exampleOfAccessingX) is valid. As I've said, this is true. But the cycle will be broken as soon as exampleOfAccessingX returns. If that local variable is the last strong reference to Ctwo, then that object will be deallocated.

  • ok, but it means that is not any weak because it's strong in scope, completely understandable. The name should be weakINscopeANDPleaseInVeryShortTime...

    1. developer decides to split connection between var/member and object so system can free object if references =0. Weak is just for that and only for it. "yes I know,

    2. but no, system have to make strong ref when I call weak().get even though I declared splitting...

    So

    "I'm a child of parent so I'm sure I live only when my parent live but I can't keep connection to parent all the time but only in scope?"

    Why? There is reallocation of memory? Pointer to parent can change during life of weak() but can't during scope? is any reason that get() is valid  only in scope?

    Yes there is misunderstanding and nervousness because there it's completely illogical, but ok not my rules and I have to conform...  But everything what was implemented in strange way should be good documented with examples and many difficult question is left with no answer.

    All examples connected with weak:

    // I would make a "Hans and Franz" reference but I
    // think certain advertising has made them uncool.
    var weakRef = obj.weak()

    //You can use the stillAlive method to check if the reference has been cleaned up.
    //Use get to create a strong reference to the object.
    //Only keep the strong reference during the scope you need it!
    if( weakRef.stillAlive() ) {
        var strongRef = weakRef.get();
        strongRef.doTheThing();
    }

    Sorry...
  • I have already checked and yes circular reference changed do weak references. But it shouldn't happen because it means that

    x = O.weak().get()

    return O instead of o.weak()

    what is the difference between:

    x = o.weak();

    y = x.get();

    and

    y = o.weak().get();

    none....

    if you are right it should run:

    var w = new weak(O).

    y = w.get()

  • "I don't know weak() return class WeakReference. Only for stillAlive? I can simple check null of object."

    Soooo, you're saying you didn't understand how weak() works but you're complaining that it doesn't work?

    "Maybe just for not increment references it has to be special class"

    Yes, that's exactly why. And that's why there's WeakReference.get() which is only supposed to be called when you need a strong reference to the object.

    Your example code

        x    = parent.weak().get();

    is no different than

     x = parent;

  • No because in exampleOfAccessingX(), the strong reference to Ctwo goes away once you're finished using it. (x is a local variable.)

    In your original example, you call parent.weak().get() right away and store the result in x (a class variable), which stays around forever unless you reassign x at some point. It's no different than if you had never used weak() in the first place. get() grabs a strong reference from a weak reference.

    It basically says so right in the docs: developer.garmin.com/.../

    Use get to create a strong reference to the object. Only keep the strong reference during the scope you need it!

    But since you never believe anything I say, let's just wait for Garmin to confirm or deny what I typed.