Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
dev42
Level 7

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. Smiley Tongue ]

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
0 Kudos
16 Replies
RokuMarkn
Level 7

Re: The quest to understand refcnt

Every time you pass an object as a function parameter, it gets another reference. The original variable in the first function still refers to it, and while the called function is executing, the parameter also refers to it.

--Mark
0 Kudos
dev42
Level 7

Re: The quest to understand refcnt

I follow that... at least I believe I do.

But, I made "the change" and am no longer sending a ref to <roScreen> to each function. Instead *when* I need it -- which could be less often assuming I fix the code where I know ahead of time that nothing is to be drawn -- in each Object's draw func:
scr = GetGlobalAA().scr
So, a local variable that is "another" reference to the original <roScreen>, yes?

So, then why does my refcnt go up from 5 to 8 when I have 3 object's drawing on screen, but all references are local and should disappear after the function closes? Yes, yes, the obvious 5 + 3 = 8 thing may apply here... but I'm more curious as to when gc [may be mixing buzzwords here] happens and/or why I have 8 references to <roScreen> when I'm no longer passing it as a parameter.

As it stands, I would think that if I wasn't careful my refcnt could go up rather high, no? Or on the other hand, shouldn't I be making sure to keep it as small and manageable as possible?
0 Kudos
RokuMarkn
Level 7

Re: The quest to understand refcnt

Yes, each time you assign to a variable like you did with scr, it increments the reference count. Not having seen your code, I'm just blindly guessing, but I imagine each of your functions looks something like this:

function one()
scr = GetGlobalAA().scr
do some stuff
two()
...
end function


So when two() gets called, scr exists and holds a ref count. Now two() probably does much the same thing, creating its own local scr variable which increments the ref count again. So even though it's not being passed as a parameter, you still have at least one variable referring to the screen in each function on the stack.

However I think you're overthinking this a bit. Your screen object persists through your whole app now, by design, so it doesn't really matter how many references it has. It never gets destroyed until your app exits.

--Mark
0 Kudos
dev42
Level 7

Re: The quest to understand refcnt

Yes, probably over-thinking...

References aren't copies. Shouldn't be too much memory use.

Part of the confusion is that they are local variables. If the function has returned then in my mind the local variable should have disappeared and along with it the reference count it held.

But yes, the code is as you said and in addition to it, a main event loop with:
for each obj in objList
obj.draw()
end for

So, that's why I thought maybe "breadth" instead of "depth" ( stack ) because the refcnt number appears to coincide with the number of objects on the screen.
0 Kudos
RokuMarkn
Level 7

Re: The quest to understand refcnt

"dev42" wrote:

Part of the confusion is that they are local variables. If the function has returned then in my mind the local variable should have disappeared and along with it the reference count it held.


That's not just in your mind, that's the truth. All local variables are destroyed when a function exits. If any of them contains an object reference, the object's ref count is decremented.

--Mark
0 Kudos
EnTerr
Level 9

Re: The quest to understand refcnt

"dev42" wrote:
( I moved it here as it really is another topic. )
You'll do well to link also where did you move it from. Not everyone (me in particular) reads every thread or in particular order.

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?
BrightScript is a case-insensitive language, so capitalization is a matter of style (or lack thereof). Java is a completely different can of worms.

roArray and roAssociativeArray are BS components, just like everything else named roSomething, see http://sdkdocs.roku.com/display/sdkdoc/Components for the list. So arrays and hashes (AA) should not be explicitly mentioned there, it will be tautology. Admittedly those two have some seemingly "magic" properties, like literal constructor/notation (a = [1,2] and d = {field: 1}), dot-operator (d.field) and indexing brackets (a[1], d["field"]) - but those are largely "syntax sugar" and result in method calls under the sheets.

OTOH the types whose name does not start with "ro" are intrinsic. Those need small amount of memory (4 bytes data), so they are passed around "as-is" values and not pointers (which is the case for roComponents). There are some quirks regarding String and Double but let's not delve into that now.
0 Kudos
dev42
Level 7

Re: The quest to understand refcnt

"EnTerr" wrote:
BrightScript is a case-insensitive language, so capitalization is a matter of style (or lack thereof). Java is a completely different can of worms.

roArray and roAssociativeArray are BS components ...

Yes, it is. I was just pointing out possible confusion. Perhaps that is what needs to be said, in the docs repeately, BrightScript iS a cAse-InSenSitIVE LanGuaGe.

As for your other comment... *snickers* Your are absoluely *snickers* correct *snickers*. Smiley Tongue

FWIW, I'm learning *more* and have just discovered that I can step thru code in the debugger... so I *should* be able to insert multiple STOP's and watch the change of the refcnt, yes? !!!!

peace & 42
0 Kudos
EnTerr
Level 9

Re: The quest to understand refcnt

"dev42" wrote:
FWIW, I'm learning *more* and have just discovered that I can step thru code in the debugger... so I *should* be able to insert multiple STOP's and watch the change of the refcnt, yes? !!!

Probably. But don't obsess about reference counts, just have faith that it works "like magic" and in most cases you have nothing to worry about, the system takes care of objects lifetime and disposal. Avoid using globals (GetGlobalAA()) when you can pass something as argument and you should be fine, since leaving out of nested functions will be cleaning behind.

For edu-tainment's sake, i made here an artificial example to demonstrate how one "memory leak" happens:
function Stack(n):
dim stk[n]
return {
stk: stk,
ptr: 0,
push: function(x): m.stk[m.ptr] = x: m.ptr = m.ptr + 1: end function,
pull: function(): m.ptr = m.ptr - 1: return m.stk[m.ptr]: end function
}
end function
...
' the following is in main()
s = stack(100)
for i = 1 to 10: s.push( createObject("roScreen") ): end for
for i = 1 to 10: screen = s.pull(): end for
screen = invalid
' at this point all roScreens should be closed, right? wrong!
...

So i got a factory function Stack(n) that constructs a stack with N elements and 2 methods, `push` and `pull` that respectively add and remove elements. Then i shove 10 roScreens on that stack, then i take them back and even invalidate the last one. And yet, they are not all gone. How come? - figuring that out will be a good exercise.
0 Kudos
dev42
Level 7

Re: The quest to understand refcnt

"EnTerr" wrote:
Probably. But don't obsess about reference counts, just have faith that it works "like magic" and in most cases you have nothing to worry about, the system takes care of objects lifetime and disposal.

In my defense, the "errors" / "misdiagnosed error/bug (proper exiting of my app)" / "redesign" of the Roku main menu / etc have lead me to be ... a tad bit "concerned" Smiley Wink

"EnTerr" wrote:
Avoid using globals (GetGlobalAA()) when you can pass something as argument and you should be fine, since leaving out of nested functions will be cleaning behind.

I don't understand what "since leaving out of nested functions will be cleaning behind" means exactly. Can you expound on it a bit?

My logic/assumption ( flawed though it might be ) was: that I was using up too much memory and/or confusing the Roku so much that it wasn't freeing memory on exit of my app. Repeated running of this caused greater and greater memory issues. As has been pointed out to me this should not have been possible, so my perception of the issues I've been having ( see response above ) are probably incorrect.

My other desire was to limit the passing of parameters unnecessarily *AND* to make the code easier to edit as a shorter parameter list seems more helpful to me.... but now that I've taken this to an extreme, passing "m" doesn't tell me much about what the function needs or will do.

AS per freeing memory: do methods, functions attached to objects, free their local variables differently than global functions?

"EnTerr" wrote:
For edu-tainment's sake, i made here an artificial example to demonstrate how one "memory leak" happens:
<see above>

So i got a factory function Stack(n) that constructs a stack with N elements and 2 methods, `push` and `pull` that respectively add and remove elements. Then i shove 10 roScreens on that stack, then i take them back and even invalidate the last one. And yet, they are not all gone. How come? - figuring that out will be a good exercise.

  • Is there something going on with the stack being initialized to 100 instead of 10?

  • and/or the pull() function only changing the ptr variable and not doing anything with the actual memory reserved in the array?

  • Arrays use contiguous memory, yet I thought I read that BrightScript does allow individual elements to be "released", am I getting warmer?

... or completely cold?

If we were to debug such a code fragment, what tools do we have to check the memory use?
0 Kudos