Adventures in tracking down a memory leak in Gliffy

Gliffy was noticeably slowing down when used for an extended period of time, and we suspected a memory leak was the cause. Fortunately, the fine folks at Laszlo have built some excellent tools into the debugger which make tracking down such issues a heck of a lot easier.

Our adventure begins with a look at the docs which discuss hunting down memory leaks. Using the procedure described in the docs, I discovered that the objects which represent undo were not being picked up by the garbage collector. Objects will not be picked up by the garbage collector if any references to those objects exist.

Laszlo Debugger

Another interesting thing I noticed was that the class definition of undo did not explicitly extend another class. When a class definition does not extend another class, it is implied that the class extends <view>, NOT <node> as you might expect. In this case, our undo object does not have a visual component to it, and as such what we really want is to extend <node>.

If you’ve instantiated Laszlo objects at run time before, you know that the first argument of the constructor is the parent node of the constructed object. In our case, it didn’t really make sense for the undo object to have a parent, and thusly none was defined. If you take a look at the source code for LaszloView.as (in the source distribution) you’ll see that when a parent is not defined in the constructor, the canvas is assumed to be the parent.

Ah-hah! We’ve found where the reference to our undo objects were coming from. Simply checking the contents of canvas.subviews in the debugger offered verification. Further investigation revealed that constructing a <node> without an explicit parent does not cause the canvas to be defined as the parent. Thusly, by simply having our undo class extend <node>, I was able to fix the memory leak. Yay!

Lessons learned:

  • Always extend <node> if there is no visual component to the class you are defining.
  • When instantiating subclasses of LzView at run-time, be aware of the implied parent if you don’t supply your own.
  • PairProgramming or code reviews probably would have caught this issue in advance. Even busy little start-ups should be taking the time to implement good code review practices.

New event syntax in OpenLaszlo

If you follow OpenLaszlo news closely, you may have noticed that a new event syntax is available in OpenLaszlo 3.2 which makes specifying and handing your own events more straightforward. I think the folks at Laszlo Systems made a smart move in adopting the new syntax as it is more intuitive, and will reduce confusion for new developers.

Curiously, the only documentation I found describing the new syntax was in this feature proposal, and in the nightly builds of the reference guide and the developers guide. Somehow the new syntax is missing from the shipping 3.2 docs.

In a nutshell the syntax is:

  • <event name="onMyEvent"/> – Declare an event
  • <handler name="onMyEvent">
    //some code here to handle event
    </handler>
  • onMyEvent.sendEvent() – notify event listeners that the event fired

Kudos to the OpenLaszlo folks for continuing to evolve the language.

Tips for using lazy & resize replication in OpenLaszlo

Here’s the scenario: I want to display 500 items in a scrolling list, but using regular replication causes 500 views to become instantiated, which can take a loooong time. Lazy & resize replication helps out by only instantiating the views that the users can see. Lazy replication then manages copying the relevant data to views that scroll into the clipped area. The dev guide explains the purpose quite well:

“The lazy replication manager creates only enough replicated views necessary to display the data, so there is not a view for each data node. This enables the display of very large datasets.”

This is great because instantiating views is expensive, and we don’t want to make any more of them than we need to. This efficiency gain comes with a price of added complexity however. Here are some tips to hopefully make your experience with lazy & resize replication a little less painful:

  • $path references don’t reliably update in lazily replicated views. Don’t waste your time using them. Use applyData() instead (more on applyData below)
  • Make sure all visual elements that might change in your replicated view are based on the data. Instead of using attributes in the view to keep track of visual information, use attributes in the dataset instead (eg this.datapath.setNodeAttribue(‘someKey’,’someValue’). You’ll probably want to use applyData() as a hook into making visual adjustments as needed.
  • applyData() is called in a replicated view whenever the data in that view changes. With lazily replicated views, applyData() is called on replicated views as the user scrolls so that data can be copied into the new LzView that just scrolled into the clipped area. Make sure that the datapath specified on the replicated view points to data that will definitely be there…. otherwise applyData() wont get fired.
  • As a workaround to the $path problem, grab any data that you need from the dataset when applyData() is fired. (e.g. this.datapath.getNodeAttribute(‘somedata’))
  • Make sure to use the dataselectionmanager if you want the user to be able to select more than a single replicated item at a time.
  • A replication manager only gets created if the datapath matches multiple nodes the first time. If there is any chance at all that you’ll match a single node, you should first set the datapath to point to a fake dataset that contains 2 or more nodes to ensure a replication manager will be created. (See the example code below)
  • You can use the fake dataset trick described above to instantiate some views upon applciation startup. This will ensure that a user doesn’t have to wait for those views to be instantiated when the real data comes in.
  • If you updated something in the dataset, and your change isn’t being reflected in the replicated views, you can try calling this.cloneManager.runXPath() from a replicated view as a last resort.

Here’s some example code that covers most of what I’ve talked about above:

<canvas>

    <!-- Let's say this is my real dataset.  It could be
         loaded from the server, but we'll make it local
         for this example -->
    <dataset name="people">
        <people>
            <person name="chrisk" sex="m"/>
            <person name="lyla" sex="f"/>
            <person name="clint" sex="m"/>
            <person name="renais" sex="f"/>
            <person name="ron" sex="m"/>
            <person name="terry" sex="f"/>
            <person name="debi" sex="f"/>
            <person name="luke" sex="m"/>
            <person name="jason" sex="m"/>
            <person name="eileen" sex="f"/>
            <person name="henry" sex="m"/>
            <person name="nik nik" sex="f"/>
            <person name="kel" sex="m"/>
            <person name="hu?" sex="f"/>
        </people>
    </dataset>

    <button text="Replcte views!">
        <method event="onclick">
            replicatedParent.datapath.setXPath('people:/people');
        </method>
    </button>

    <view width="100" height="100" clip="true">
        <!-- use this dataset to ensure a
             replciation manager is created, and also
             create some views on applciation startup
             so that the user doesn't have to
             wait when they request the data  -->
        <dataset name="fakeData">
            <people>
                <person/> <person/> <person/> <person/> <person/> <person/>
            </people>
        </dataset>

        <view id="replicatedParent"
              datapath="local:parent.fakeData:/pepople">
            <text>
                <datapath xpath="person/@name"
                          replication="lazy"/>

                    <!-- Is called when a user scrolls the data into view -->
                    <method name="applyData" args="_d">
                        super.applyData(_d);

                        if( this.datapath.getNodeAttribute('sex') == 'm' ) {
                            this.setBGColor(0xCACAFF);
                        } else {
                            this.setBGColor(0xFFCACA);
                        }
                    </method>
            </text>
        </view>
        <scrollbar/>
    </view>
    <simplelayout axis="y"/>
</canvas>

My Top Laszlo Performance Tips

A customer recently asked if I had a list of Laszlo coding, performance, & style tips. I didn’t, so I thought I’d start by creating a list of performance tips. Anyway, here’s my list (in no particular order)

  • When using constraints, use $once{} as often as possible – Constraints are a great time saver, but they come at a cost. Normal constraints have to have their events registered when the application starts up, so if you have a lot of constraints, this can slow things down. If you don’t need the constraint to update after application startup, use $once{} for an incremental performance improvement.
  • Use short variable names – I believe this was more of an issue with older versions of the Flash player, so I’m not sure how relevant this is, but it is my understanding that because of the nature of Javascript, long variable names actually have a negative performance impact. If you look at any of the Laszlo run time source code, you’ll see most of the variable names are VERY short, to the point that it makes the code hard to read.
  • Use pooling and lazy replication for replicated views as often as possible – Take advantage of the hard work Adam put into making these features work. Pooling reuses previously replicated views, improving the rendering time when a datapath is updated. Lazy replication only replicates the visible views, hence saving lots of time in the event you have a scrolling list of say hundreds of replicated nodes. You’ll likely need to tweak your code to get these two features to work, but the performance gain you get is totally worth it.
  • Minimize the number of views used – Views are expensive to instantiate, so do what you can to minimize the number of views generated. Focus on classes that are constructed often via replication or other means. For example, in our diagram editor every shape contains ‘connection points’ which are represented by little ‘+’ symbols. Originally, we created the ‘+’ with two views (one horizontal, and one vertical). By using a single asset for the ‘+’ symbol, we cut the number of constructed views down substantially for each shape, yielding faster diagram load times.
  • Load images at run-time – If you don’t need to display an image right away, consider loading the image at run time to reduce the initial application download size.
  • Delay instantiation – Delay instantiation on any views that wont be shown right away to improve start-up performance. For example pop up windows, drop down menus, etc.
  • Use local variables when possible – I think this is another issue that is less important with the newer Flash players, but probably worth looking into. Apparently accessing global variables can be slow, so you’re better off creating a local reference to the global variable if you are going to access it a bunch in a loop.
  • Using Debug.write() can slow things down even when the debugger is off – If you want to be fancy, you could do something like if( $debug) Debug.write(‘some message’); The compiler is smart enough to remove the $debug statements kind of like a pre-processor.

Did I miss anything? Feel free to clue me in, and I’ll add to the list here.

OpenLaszlo Performance Tip: offsets

I’m not sure if Laszlo Systems would approve of this, but I found something that improves the speed of rendering views that are changing their dimensions or positions rapidly. In our application, we need to resize and move many views all at the same time, repeatedly. During all this, we also need to adjust xoffset and yoffset since these views might be rotated. All this view morphing puts a heavy strain on the system, and performance noticeably suffers as a result. I was poking around in the OpenLaszlo source code, and discovered that when you set the xoffset or yoffset attributes using setAttribute(), setX() and setY() are invoked internally.

Our code looked something like this:

   while( aBunchOfTimes ) {
        //setX() and setY() invoked internally by LzView
        someView.setAttribute('xoffset', someView.width/2 );
        //setX() and setY() invoked internally by LzView
        someView.setAttribute('yoffset', someView.height/2 );
        someView.setX( anewx );
        someView.setY( anewy );
    }

In the above case, setX() and setY() are being invoked a total of 6 times. It turns out that setX() and setY() and costly enough operations that this is worth optimizing. How do we speed things up? I went ahead and changed the above code to look something like this:

   while( aBunchOfTimes ) {
        someView.xoffset = someView.width/2;
        someView.yoffset = someView.height/2;
        someView.setX( anewx );
        someView.setY( anewy );
    }

What’s going on here? setAttribute(‘xoffset’) and setAttribute(‘yoffset’) cause internal functions to be invoked which in turn invoke setX() and setY(). If you assign a value to xoffset and yoffset directly, as I’ve shown in this last example, the internal functions are not invoked. When I finally do invoke setX() and setY() on my own, the OpenLaszlo view system does whatever it needs to do with xoffset and yoffset to keep everything in order. It turns out this simple change made a very noticeable performance improvement in our application. (Clint said, “It’s smooth like butter!”)

Yay for open source!

It’s important to note that this optimization now depends on specific internal behavior of the OpenLaszlo view system. Obviously, this goes against the rules of code abstraction, and we run the risk that our application might break if the internal workings of the OpenLaszlo view system change significantly. In our first round of user testing, we found that performance was a significant factor in making happy users, so we think this risk is worth it.

RIA’s will spawn a new breed of web based applications

Get ready folks, Rich Internet Applications (RIA’s) will soon have you doing things on the web which you thought were only possible with desktop applications. These new web based applications will soon have you collaborating in ways you never thought possible, increasing the overall efficiency of companies in many ways. Here are a few interesting reads which all point in this general direction:

What could this all mean? I have a few predictions:

  • As RIA alternatives begin to arrive on the scene in the next 1-2 years, progressive folks will stop using traditional desktop applications, including ALL Microsoft Office products.
  • Lighter weight RIA alternatives to traditional desktop applications will offer collaboration opportunities far beyond those which are available in their desktop counterparts.
  • Microsoft knows this trend is in the works, and will be mostly helpless to stop it until Windows Vista has greater market share.
  • Many of Microsoft’s big money making software titles will be threatened. Microsoft stock will take a big hit when this trend becomes clear to the masses.
  • Microsoft will find a way to create problems for RIA’s. A few possible scenarios:
    • The new version of IE will break existing AJAX RIA’s in subtle ways
    • The new version of IE wont play well with Flash, causing trouble for Flash based RIA’s like OpenLaszlo and Flex applications
    • Microsoft will create and bundle it’s own Flash player, breaking Flash based RIA’s which threaten their desktop application dominance.
  • SocialText and JotSpot will be leading the charge (if they don’t get acquired by Yahoo or Google first)

What do you think?

Is OpenLaszlo right for your project?

Even as a former employee of Laszlo Systems, deciding which Rich Internet Application framework to use for the new venture was harder than I thought it would be. Clint and I really wanted to use OpenLaszlo, but AJAX was making headlines. Furthermore, AJAX/DHTML applications were being successfully deployed all over the place. Even though it’s challenging to question using a technology that you’ve invested 2 years of your career on, when starting a new company, you better do it or risk paying for that decision later.

Some pros of OpenLaszlo include:

  • Clint and I know LZX, Laszlo’s markup language, really well (Clint was the lead developer on the ColorSmart Application for Behr Paints).
  • Since Macromedia tightly controls the Flash web browser, you can be sure that 99% of what you write will run in any browser that has flash 6 or higher installed. (At the time of this writing, Macromedia claims that flash 6 or higher is running in over 96% of web browsers out there)
  • At the moment, LZX is a lot more elegant, and fun to write when compared to AJAX. (though, there are several frameworks out there that are trying to change this)
  • LZX gives you constraints, delegates, animation, data binding/replication out of the box for free
  • No need to cobble together scraps of code from all over the place to build a framework…. it’s all there for you in one nice place
  • OpenLaszlo is open source, making deployment costs much lower. We thought we had enough experience with Laszlo that we could get by for a while without paying for support.

Some pros of AJAX include:

  • There are many examples of deployed AJAX applications out there. The developer community around DHTML/AJAX/whatever has been around a LONG time.
  • It’s not flash. Be it justified or not, developers are always wary of flash. I think this has something to do with the gratuitous flash animations that you occasionally see misplaced on corporate web sites. For our purposes, if we ever expected to sell our application, developers have to see this as something they could work with.
  • Javascript in the web browser is WAY faster than it is in flash. While this isn’t too much of an issue in Laszlo apps on fast hardware, slower hardware can have some issues in certain situations

(If you think I’m missing something critical in these lists, feel free to let me know and I’ll update it)

So what did we decide? We eventually concluded that utilizing our Laszlo skills would give us a competitive advantage, and decided that whatever project we choose to chase down (there were many) should be something that Laszlo is perfectly suited for, and would either be impossible or really hard to do in DHTML. We are really excited about the project we’ve started working on, and can’t wait to show it off soon!

Need help deciding if OpenLaszlo is right for your project? For a limited time, I’m available for one day consulting gigs. Email me at: