CaptainStealthy
CaptainStealthy

Reputation: 388

ASP.NET web service causes a memory leak in Adobe Flex/AIR app

We've released a basic iOS app (built with Adobe Flex/AIR using FB 4.6) for a newly-released software product, and I have been tasked with making enhancements to the app, to essentially bring it's functionality more up to snuff.

I have made quite a few improvements, with varying degrees of success along the way. But, I digress.

I have discovered what appears to be a serious memory leak in the app, which went undetected until now.

The initial release of the app didn't do a whole lot, and it was adequate for most purposes. But now that it contains a lot more functions, I noticed in my testing that it was a bit sluggish on an iPad. I chalked it up to being a device issue, and guessed that the first-gen iPad wasn't as powerful as the newer iPads.

We tested the app on a co-worker's iPad 3, and found the same sort of speed issues. I ran the app through FB's profiler, and found that it seemed to be using very high amounts of memory. Granted, this app is targeted towards mobile platforms, and the profiler was running the app in Flash Player within Windows, but I'm assuming that is the issue.

The first view that appears in the application is simply a login screen. I watched the graph as the application started, and the memory usage was hovering pretty low, and then all of a sudden, it spiked to 120MB. This was with no input from the user. Logging in or switching views would make the usage double, or even triple, and it would never come down.

I'll admit, maybe I wasn't as conscious about resource usage as I should have been, but I have been trying to clear objects and such as I go.

Most of the back-end functions are done via calls to a web service written in ASP.NET. The web service is plugged into Flash Builder using the Web Service wizard...the URL for example would be http://www.mydomain.com/MyWebService.asmx?WSDL

The first "home" view does not call any of the web service functions unless the user actually DOES something, such as press a button. I took out the web service declaration from the "fx:Declarations" section of the view, and commented out any references to it, and tried the profiler again.

This time, the usage capped out at 2MB. That is an astronomical difference.

The profiler showed that 99% of the memory was being used by the "XML" class, which led me to believe that the web service was the problem. It almost seems like the view is querying the web service on startup, and is using high amounts of memory in order to do so.

Am I missing something here? Is there a more efficient way to call a web service from an AIR app? What am I doing wrong?

Thanks in advance!

Upvotes: 1

Views: 465

Answers (1)

CaptainStealthy
CaptainStealthy

Reputation: 388

I think I finally figured it out!!

This post is a public service for others who may encounter the same issue.

I'm not sure why the web service causes spikes in memory usage like that, but I was able to work around it. The usage still spikes to just below 120MB in my case, but the difference is, when I switch views, it doesn't double/triple like it was doing before.

Credit to Amy for leading me in the right direction. I basically took out all of the declarations and such to the web service, and declared it publicly in the application MXML file, like so.

public var ws:WebService = new WebService();

protected function viewnavigatorapplication1_preinitializeHandler(event:FlexEvent):void
{
    ws.loadWSDL("http://www.mydomain.com/MyWebService.asmx?WSDL");
}

Then in your views...

private var serviceOperation:AbstractOperation;
private var myToken:AsyncToken;

private function getData():void
{
    var firstName:String = "John";
    var lastName:String = "Smith";        

    serviceOperation = this.parentApplication.ws.getOperation("MyFunction");
    serviceOperation.addEventListener(FaultEvent.FAULT, fault);
    serviceOperation.addEventListener(ResultEvent.RESULT, result);

    myToken = serviceOperation.send(firstName, lastName);
}

public function result(data:Object):void
{
    switch(data.token)
    {
        case myToken:
            processResults(data);
            break;
        default:
            break;
    }
}

And obviously, make sure to remove event listeners and set your object references to null when you are finished with them. I did this for the token and the operation, to be safe.

I haven't tested the app thoroughly for the memory usage, but on first glance, it wasn't increasing exponentially, and I believe I even saw it come down when the garbage collection kicked in.

Upvotes: 1

Related Questions