Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
EnTerr
Roku Guru

Re: The quest to understand refcnt

"dev42" wrote:
I don't understand what "since leaving out of nested functions will be cleaning behind" means exactly. Can you expound on it a bit?
Sure. Let's say in a sub A() you create a roScreen (or another huge chunk of data, say parsed multi-megabyte xml) and then you call from there sub B(), C() etc by passing that as argument. Each of them in turn may call sub-routines B1(), B2() etc as they see fit and may or may not pass the big structure to them. As long as none of them reaches out of its scope (local vars and fn args) to store roScreen in a global variable, you can be sure that when they return, ref-cnt will be back to 1 and on exit from A() the object will be disposed - you don't even have to explicitly set the variable to invalid.

If on the other hand you store roScreen in a global from A() (or any sub-ordinates that A() calls), then it will survive past A() call life - unless you remember explicitly to invalidate the global variable just before exiting from A(). Now "remembering" to do something is not awfully hard but there could be complications. Say mid-function you have some urgent exit with RETURN, since some pre-condition is not met and there is no point of doing the rest - 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.

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.
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)

AS per freeing memory: do methods, functions attached to objects, free their local variables differently than global functions?
No.
The only difference is they get variable `m` pre-set to the dictionary that "owns" them, while global functions have GetGlobalAA() pre-shoved in their `m`.

"EnTerr" wrote:
For edu-tainment's sake, i made here an artificial example to demonstrate how one "memory leak" happens: ...
  • 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?
Warm on the 2nd, cold on the rest.

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

I personally use strategically placed STOPs (or ctrl-C) and PRINT, sometimes VAR and DA (DisAssembly, shows p-code). Alas, seems recently Roku has more taketh than giveth - now DA does not work.

Why RokuCo, WHY?!?
0 Kudos
dev42
Visitor

Re: The quest to understand refcnt

"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.
0 Kudos
EnTerr
Roku Guru

Re: The quest to understand refcnt

"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!)
0 Kudos
RokuMarkn
Visitor

Re: The quest to understand refcnt

"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
0 Kudos
dev42
Visitor

Re: The quest to understand refcnt

"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
0 Kudos
RokuMarkn
Visitor

Re: The quest to understand refcnt

"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
0 Kudos
dev42
Visitor

Re: The quest to understand refcnt

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?
0 Kudos