[Laszlo-user] Understanding memory analysis when using _LzDebug.whyAlive()

P T Withington ptw at pobox.com
Wed Apr 9 10:51:26 PDT 2008


[cc-ing Lou.  We need to improve the documentation on the Debugger  
memory tools.  I thought I had written something, but I can't seem to  
find it, and the current doc

http://www.openlaszlo.org/lps4/docs/developers/debugging.html#d0e121455

is confusing even to me.  I've attached some additional info to the  
end of this message.]

On 2008-04-09, at 11:27 EDT, Gilad Parann-Nissany wrote:
> Hi
>
> We're trying to optimize our memory usage, not exactly find leaks  
> but profile our memory. We are on OL 4.0.8.
>
> So far we've used _LzDebug.whyAlive() to analyze an application; is  
> there a different recommended way to analyze the memory allcoation  
> of an OL app? or are we doing the right thing?

That's the best tool we have for fine-grained analysis.  I also use  
the operating system's memory profile tools to see if my application  
is growing without bound, although this is a very 'noisy' measure,  
because all you can look at is the total memory of the browser.  If  
you are _only_ running your application in the browser, it is quite  
likely that any fluctuation in memory usage is due to your  
application, but also note that most runtimes will only garbage  
collect when your application is idle.  Sometimes minimizing the  
browser window will trigger a garbage collection.

> Attached a screenshot of an example run. We need help to understand  
> this output:
>
>    • what are smoots?

An small (inside) joke:  http://en.wikipedia.org/wiki/Smoot

>    • why do objects contain smoots?

Since the memory leak detector is running in the SWF or DHTML virtual  
machine, it has no way to actually measure the size of an object in  
bytes.  It approximates the size of an object by counting the objects  
properties, and by assuming some reasonable defaults for built-in  
objects like numbers and strings.  Smoots should be proportional to  
bytes, but they are not bytes.

>    • what are the numbers that start with a pound-sterling sign? in  
> regular paranthesis like Array(4)?  with "#" like in Array(4) #262

This is intended to represent the 'total weight' of the object.  It is  
the sum of the object's smoots and the smoots of it's children and  
it's children's children, etc.

>    • how to interpret the names on the leftmost side such as  
> global.spriteroot? the ones after the colon?

This is the shortest path from the root to the object, the most likely  
reason the object is still 'alive'.  (There may be other links to the  
object, but the tool only records the shortest one.)

> is there any way we can translate these into bytes of memory? we  
> have measured total RAM used separately, but would like to know  
> whether the result of whyAlive is a dependable measure of the  
> breakdown of this memory...

As above, smoots should be proportional to total memory.

---

[Additional info]

As of 4.0.8, there are some fixes for the leak detection tools.  The  
leak detector no longer gets fooled by getters in the runtime that  
return a new object each time you access a property.  You no longer  
have to go through hoops to get the output of `Debug.whyAlive()` -- it  
prints out a useful summary again, and if you inspect the result, you  
get the full report.  Each element in the leak report is also  
inspectable.  Ex.:

> lzx> Debug.markObjects()
> Marking objects ...
> lzx> DEBUG: 7 loops @ 1379 iterations, 1137.97 milliseconds
> ... done!
> lzx> Debug.findNewObjects()
> Finding new objects ...
> lzx> DEBUG: 7 loops @ 1379 iterations, 1153.63 milliseconds
> ... done!
> lzx> Debug.whyAlive()
> 82 smoots [4 objects @ ~21 smoots each]:
> global.spriteroot.$m1.debugloader.loadmc1.reqobj: (£54) «Object#138|  
> {_dbg_check: 54, _dbg_smoots...»
> global._componentmanager.service.upkeydel: (£20) «LzDelegate#141|  
> «lz._componentmanager».d...»
> global.LzKeys.downKeysArray: (£8) «Array(2)#144| [16, 68]»
> .: (£0) «¿movieclip?»
> «__LzLeaks(4)#136| 82 smoots [4 objects @ ~21 smoots each]»
> lzx> Debug.inspect(82 smoots [4 objects @ ~21 smoots each])
> «__LzLeaks(4)#136| 82 smoots [4 objects @ ~21 smoots each]» {
>  constructor:         __LzLeaks
>       length:         4
>            0:         global.spriteroot. 
> $m1.debugloader.loadmc1.reqobj: (£54) «Object#138| {_dbg_check: 54,  
> _dbg_smoots...»
>            1:         global._componentmanager.service.upkeydel:  
> (£20) «LzDelegate#141| «lz._componentmanager».d...»
>            2:         global.LzKeys.downKeysArray: (£8)  
> «Array(2)#144| [16, 68]»
>            3:         .: (£0) «¿movieclip?»
> }«__LzLeaks(4)#136| 82 smoots [4 objects @ ~21 smoots each]»
> lzx> Debug.inspect(«__LzLeak| global.LzKeys.downKeysArray: (...»)
> «__LzLeak#151| global.LzKeys.downKeysArray: (£8) «Array(2)#144| [16,  
> 68]»» {
>  constructor:         __LzLeak
>       leaked:         8
>          obj:    (£8) [16, 68]
>       parent:         #LzKeys
>         path:         'global.LzKeys'
>     property:         'downKeysArray'
> }«__LzLeak#151| global.LzKeys.downKeysArray: (£8) «Array(2)#144|  
> [16, 68]»»

This shows inspecting the memory report '__LzLeaks', which has four  
leaks reported, and then inspecting an individual leak report  
'__LzLeak', which has the amount 'leaked', the 'obj'ect that the  
report is about, the 'parent' of that object (the object that is  
referencing the reported object, the 'path' from the root to the  
parent, and the 'property' of the parent that contains the reported  
object.

Hope this is helpful.  Let me know if there are further questions.





More information about the Laszlo-user mailing list