Forum Discussion

dev42's avatar
dev42
Visitor
11 years ago

The quest to understand refcnt

"RokuMarkn" wrote:
The ref count is the number of variables referring to the object. It's set to 1 when you do CreateObject, and it get incremented every time a new variable is set to refer to that object, and decremented every time any such variable is modified or destroyed.

In answer to another one of your questions, all local variables are destroyed when the containing function exits. There is no need to set a variable to invalid unless it's going to remain in scope.

Also, I've updated section 4.3 of the Brightscript Language Reference to explain a bit more about references and such. I'd appreciate any feedback if it isn't clear.

--Mark
( I moved it here as it really is another topic. from, here)

linky (Area 42 errr section): 4.3 Intrinsic types and object types

[Edit: Just noticed section 4.4 Use of wrapper functions on intrinsic types, which may null and void some of my comments. Maybe. 😛 ]

Feedback:
  • Capitals "issue"(?)/ possible confusion: doesn't Java designate lower case as intrinsic and first letter Capital as Object? Furthermore, you weren't consistent and used "integer" further down. Yes, BrightScript is BrightScript and can/should have its own conventions. ( Sorry if nitpicking, but trying to err on helpful. ) Perhaps expand, "An object type is one of Array, Associative Array or Brightscript Component." to include more BrightScript correct code? ie roArray, roAssociativeArray? Or is there an instrinsic "Array" type too? Also make connection between Integer and roInt? roString etc and/or make a table to show the intrinsic type in one column and the BrightScript object in another? Although that might just be more confusing. Dunno.
  • In first example, could you add: b = 2319 ' does not modify a ( For those ... like moi. )
  • the part about autoboxing no longer being necessary went over my head.

Other than that, I'm still baffled why I had 5 refcnts to my roScreen. I'll have to dig into the code, but if I'm passing the <roScreen> as a parameter ( something I'm ready to change very soon, now that I've found GetGlobalAA() ) it seems to me that all the references are the parameters in these functions. Maybe I'm "seeing" it incorrectly and there are in fact many references to the same <roScreen> but instead of depth it is breadth? :idea: IOW, if I have a roList of Objects and each object has a reference to <roScreen> then they would all stay active as long as each Object in my roList stays alive? As Belt would say, "Dun-dun-dunnnnnn!"

peace & 42

16 Replies

  • "EnTerr" wrote:
    ... and boom, you forgot to do the cleaning at function's end. To do it right, you'd have to GOTO the end segment or cascade your code to the right by using extra IFs.

    • if "home" is pressed, does gc get called? Yes, but ... not the same as if the app closed correctly? In light of the potential mess of refcnt's.
    • what if... only *ONE* area assigns globals and everywhere else accesses them?
      ' *** setup globals here ***

      ' init obj's
      for each obj in objList : obj.init()

      while true
      ' *** do Roku Event/Msg thing here ***

      ' process event
      for each obj in objList : obj.doEvent(e)

      ' draw ea. obj
      for each obj in objList : obj.draw()
      end while

      for each obj in objList : obj.close()

      ' *** close globals here ***
    • a third point, because there have to be at least 3


    "EnTerr" wrote:
    You got it - things should be done in moderation.
    Regarding passing "unnecessarily", let me give you this to mull about: using variable `X` passed as an argument is MUCH faster that using `m.X`. This is because in B/S dot-operators are dictionary lookups behind the scenes. Yes, every time - even in a loop. (I am not saying don't use m.X, just know "unqualified" X is faster)

    To reiterate what you just said, "passed as an argument" ... specifically emphasizing "sending", right? So, what's better/preferable: ● B(m.loc) ● B(m.loc.x, m.loc.y) ● B(m)? ... when B() is called by A() and A() is most likely being called every time through the main loop!

    "EnTerr" wrote:
    Warm on the 2nd, cold on the rest.

    So, you're just decrementing your own internal size counter, but never releasing any of the array's individual elements, right? You could, but not with your code, still access s, even when ptr < x.

    Your demo-code confuses me & is a construct I've not fully accepted ( it's not in my quiver ). How is s.push() or s.pull() even allowable if the stack function requires a parameter? ( Never-mind. It's the formatting. I'm doing the same thing in long format. Not only that, I don't [yet] use the ":" trick in my actual code. ) For clarity, the dim is only called once, right?

    "EnTerr" wrote:
    Why RokuCo, WHY?!?

    I do not work for them(yet 😉 ), but I could give my 4.2 cents ... would you consider going to NDK/Marmalade?

    :idea: why don't you and TheEndless consider joining forces and hiring me? Together we could take over the world! After we find hot-pants in our size, of course.
  • "dev42" wrote:

    • if "home" is pressed, does gc get called? Yes, but ... not the same as if the app closed correctly? In light of the potential mess of refcnt's.

    • what if... only *ONE* area assigns globals and everywhere else accesses them?

    • a third point, because there have to be at least 3

    • memory will be freed no matter how app was exited. It's matter of good style to clean up after oneself - just like closing open files before exiting a C/Java/Python program ("yes, the OS will take care of it but you do it regardless" - they'd tell you)

    • that's fine if it suits your fancy

    • point acknowledged


    To reiterate what you just said, "passed as an argument" ... specifically emphasizing "sending", right? So, what's better/preferable: ● B(m.loc) ● B(m.loc.x, m.loc.y) ● B(m)? ... when B() is called by A() and A() is most likely being called every time through the main loop!
    Well that depends on what exactly are you doing. I would say write whatever seems natural to you at first. Luckily in B/S whatever comes naturally - laziness, do less typing - is also faster. Working with a local variable ("x") is an order of magnitude (> 10x) faster than "dotting" as m.x (regardless whether for global or object member). SImplifying a little bit here: m.x is just syntax sugar for m["x"]. Using global functions and local variables is fast, anything that involves a dot - not so much. Don't get all crazy on me now and banish object use completely. Optimize later, you may not need it. (RokuMarkN frowns when i talk about performance, i know 8-) Sorry).

    It's usually the loops you get to worry about, where most of the time is spent. The mouthful "loop-invariant expression hoisting" simply means avoid repeating the same work over and over in the loop - move it outside. E.g.

    for i = 1 to lineLen
    m.loc.x = m.loc.x + dx
    m.loc.y = m.loc.y + dy
    plot(m.loc.x, m.loc.y)
    end for

    ' loop-invariants moved out, much faster
    x = m.loc.x : y = m.loc.y
    for i = 1 to lineLen
    x = x + dx
    y = y + dy
    plot(x, y)
    end for

    So, you're just decrementing your own internal size counter, but never releasing any of the array's individual elements, right? You could, but not with your code, still access s, even when ptr < x.
    You got it!
    In pull() I should have invalidated the element at the ptr... after returning it :twisted: Ugh! Yeah, temp variable is in order:
    function(): m.ptr = m.ptr - 1 : res = m.stk[m.ptr] : m.stk[m.ptr] = invalid : return res : end function
    Or of course, i could have avoided re-inventing the wheel and just used roArray.push() and .pop() instead of rolling my own but that wouldn't have allowed me to demonstrate a "memory leak", now would it.

    Your demo-code confuses me & is a construct I've not fully accepted ( it's not in my quiver ). How is s.push() or s.pull() even allowable if the stack function requires a parameter? ( Never-mind. It's the formatting. I'm doing the same thing in long format. Not only that, I don't [yet] use the ":" trick in my actual code. ) For clarity, the dim is only called once, right?
    Sorry - i don't usually write so dense but in the forum i go to great lengths to make code short so it can be easy to see at a glance - preferably without scroll bar at the code box.
    - Stack() is just an "object factory" function (or "constructor") - when called, it makes and returns an object you can continue beating at own leisure.
    - DIM looks declarative but is in fact executable statement, with dim stk being thereabout equivalent to stk = createObject("roArray", n, true). So each time Stack() is called, new array is allocated and assigned to stk at that line.

    ---
    (this Reply has been hanging open in my browser for a week so... Submit!)
  • "EnTerr" wrote:
    (RokuMarkN frowns when i talk about performance, i know 8-) Sorry).


    Indeed. Far FAR more important than performance is how the various choices affect the structure and maintainability of your code. Generally global variables are evil. There are some cases where globals are appropriate, but if you're not sure whether a variable should be global or not, it shouldn't.

    --Mark
  • "RokuMarkn" wrote:
    Indeed. Far FAR more important than performance is how the various choices affect the structure and maintainability of your code. Generally global variables are evil. There are some cases where globals are appropriate, but if you're not sure whether a variable should be global or not, it shouldn't.

    --Mark


    I totally agree that maintainability is more important and one shouldn't seek performance/optimization too early ( thank you Mr. Knuth ), but it might be valid to consider possible methods of optimization early on the development process to allow for those changes later without having to "fix" more things.

    Beyond that, I have issues with:
    "RokuMarkn" wrote:
    Generally global variables are evil.

    Why are global variables evil? I'm asking honestly. Furthermore, if a couple examples of alternatives could be given that would be much appreciated. I am in a stage of refactoring what I have in order to make updating and expanding my app more effortless.

    Are Set-ers and Get-ers related to all this? If so, wouldn't they just be Setting & Getting global variables?

    And for clarity, I'm dealing with ... AFAICT ... situations where the "grandchild" should know something about the "grandparent". OK, I may be mixing my metaphors, but something like this: A.doSomething() -> B() -> C() and C() needs to know things about "Object" A and I've just gotten to the point where I didn't want to keep sending parameters or give access to *all* of A via passing "m" all the way down the chain.

    Edit: As I sit here and ponder all this it starts to dawn on me that I could make a Set/Get with 2 params, the variable and the value. That way it wouldn't have to be a global var, but I'm still limited in how the function would have access to that object.

    peace & 42
  • "dev42" wrote:

    Why are global variables evil?


    Well I'm sure you can find hundreds of essays on this topic on the web. Basically global variables have unlimited scope, and can be accessed and modified anywhere. This makes code harder to analyze. For example:

    a = 100
    func1(a)
    func2()
    a = func3()

    In this code, it's trivial to see that func1 uses the value of a but doesn't modify it, func2 neither uses nor modifies it, and func3 modifies it without using it. You also know that just before func3 is called, a still has the value 100.

    Now look at it with globals:

    m.a = 100
    func1()
    func2()
    func3()


    In this case, suppose the data access is the same, func1 uses m.a, func2 neither uses it nor modifies it, and func3 modifies it. You can't tell any of this by looking at the calling code. You'd have to go read every line of func1, func2 and func3 to determine what they do (if anything) with m.a. Limiting the scope of variables makes it easier to keep track of how data is used.

    Global variables are a big topic and this is just one aspect of it. I'd suggest you read up on it if you're interested.

    --Mark
  • I appreciate the response and example. Yes, I do realize it is a "hot topic" (googleable) and your example does prove something. Yet, it doesn't solve my dilemma of needing access to data that the current function's "m" ( this pointer / scope ) doesn't provide.

    To avoid the use of Global Vars (everywhere!), I've passed a reference to the parent object on to what I thought was the child object. In another thread TheEndless pointed out that I may be creating circular references by doing this. Since I don't get any "orphan" message on screen, I'm going to assume I'm not exactly doing this with child "objects" but with 2 & 3 hop "nested" functions. Either way, it seemed that this was a possibility the refcnt seemed higher than -- I thought -- it needed to be. But it was one way to avoid creating more and more global vars.

    But in regard to the use of global variables, my current use is limited to (a) Setting them once early and then only getting them through-out the code or (b) as something that everybody can access / change / etc who's "value" doesn't matter as it is wiped out every-time through the loop. IOW, a bitmap. No need to Create it everytime it is needed and I'm still not sure -- in this case -- the benefit of not using a global variable.

    Other than that, I've been attempting to separate function from form. So, I could change the display of the data without having to deal with anything in regard to the code that deals with the data. I'm not sure what this is called... good programming practices? 😉 or is there a buzzword, like something similar to MVC ( Model View Controller ) type thing?