Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Adobe AIR Development

Reply
New Developer
luko
Posts: 48
Registered: ‎06-26-2011
My Device: Blackberry Playbook
Accepted Solution

BB10 URLStream memory leak

[ Edited ]

I am using this code to download large files from server. It works fine on PlayBook OS (I can download even few Gigs files), but when I use it in the same application on BB10,  it crashes after downloading about 300MB.

I noticed that it crashes because memory is full. 

 

package
{
	import flash.events.*;
	import flash.filesystem.*;
	import flash.net.*;
	import flash.utils.*;
	
	public class SaveFile
	{
		
		private var _file:File = null;
		
		private var _URLStream:URLStream;
		private var _fileStream:FileStream;
		
		private var _downloadComplete_bool:Boolean = false;
		private var _pos_int:uint = 0;
		
		public function SaveFile($path:String = "", $file:File = null)
		{

			this._file = $file;
			
			_URLStream = new URLStream();
			_fileStream = new FileStream();
			
			var _request:URLRequest = new URLRequest($path);
			
			_fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onOutputProgress);
			_fileStream.openAsync(_file, FileMode.WRITE);
			
			_URLStream.addEventListener(ProgressEvent.PROGRESS, onProgress);
			_URLStream.addEventListener(Event.COMPLETE, onComplete);
			_URLStream.load(_request);
		
		}
		
		private function onComplete(e:Event):void
		{
			
			if (_URLStream.bytesAvailable > 0)
			{
				
				var _bytes:ByteArray = new ByteArray();
				var _start:uint = _pos_int;
				_URLStream.readBytes(_bytes, _start);
				_fileStream.writeBytes(_bytes, _start);
				
			}
			_downloadComplete_bool = true;
		}
		
		private function onProgress(e:ProgressEvent):void
		{
			var _bytes:ByteArray = new ByteArray();
			var _start:uint = _pos_int;
			_pos_int += _URLStream.bytesAvailable;
			
			_URLStream.readBytes(_bytes, _start);
			_fileStream.writeBytes(_bytes, _start);
		}
		
		private function onOutputProgress(e:OutputProgressEvent):void
		{
			if (e.bytesPending == 0 && _downloadComplete_bool)
			{
				
				_URLStream.close();
				_fileStream.close();
				_file.downloaded = true;
			}
		}
	
	}

}

Do You know any workaround for this problem? I've tried to set ByteArray to null after every write operation but it doesn't change anything.

 

Thank You in advance.

I hope You can help.

 

Developer
Developer
mdd
Posts: 225
Registered: ‎01-17-2012
My Device: PB

Re: BB10 URLStream memory leak

On PB OS, I found reading from the network to be much faster than writing to a device file, leading to excessive growth of the write buffer.  I solved it by monitoring the output progress and blocking reads whenever the pending write exceeds a maximum:

const MAX_READ    : Number = 0x100000;
const MAX_PENDING: Number = 4 * MAX_READ;
            
var readBlocked:Boolean = false;   

var onOutputProgress:Function = function( e:OutputProgressEvent ):void { bytesPending = e.bytesPending; } var onProgress:Function = function( e:ProgressEvent ):void { var t:Number = new Date().time; if ( bytesPending > MAX_PENDING ) { readBlocked = true; } else if ( stream.connected ) { stream.readBytes( bytes, bytes.length, Math.min( stream.bytesAvailable, MAX_READ ) );

 Same code seems fine on BB10, but I have only tried on the simulator (which I suspect can write fast enough to keep up with reading).

 

Some stats:

streamFile - load complete:
                httpStatus: 200
              httpResponse: null
           response delays:  00:00.147  00:00.149  00:00.150
                   elapsed:  00:20.637
                bytes read: 29.8 Mb
                 available: avg. 28.0 Kb / max. 192 Kb / min. 4.24 Kb
                   pending: avg. 27.5 Kb / max. 496 Kb
streamFile - buffer closed - delay: 13 (ms)

 In this case, no reads blocked...

 

Regards,

New Developer
luko
Posts: 48
Registered: ‎06-26-2011
My Device: Blackberry Playbook

Re: BB10 URLStream memory leak

Thank You for help mdd.

I tried to block reading of stream but it doesn't work :/

Maybe it's something wrong with AIR runtime or OS is not freeing RAM properly

(AFAIK in Blackberry 10 phones will have 2GB of memory, dev Alpha has got only 1)

 

Developer
jtegen
Posts: 6,541
Registered: ‎10-27-2010
My Device: HTC One, PlayBook, LE Z10, DE Q10

Re: BB10 URLStream memory leak

What happens if you insert:

System.gc();

??
New Developer
luko
Posts: 48
Registered: ‎06-26-2011
My Device: Blackberry Playbook

Re: BB10 URLStream memory leak

Garbage collector doesn't fix this problem :/

I tried to use it after every write operation but application crashes every time after downloading 100 - 300 MB of single file.

It works fine with small files but I can't download file larger than 300 MB.

My network is not very fast (download speed is approx. 600KB/s).

 

I think it may be URLStream using all available memory when downloading file.

Shouldn't it be cleared afer every write file operation?

 

 

Thanks for Your help.

Developer
jtegen
Posts: 6,541
Registered: ‎10-27-2010
My Device: HTC One, PlayBook, LE Z10, DE Q10

Re: BB10 URLStream memory leak

Can you run it from the desktop as standard AIR app? Could it be a timeout issue since you said your network is slow. Can someone else test it against the same resource?
Developer
Developer
mdd
Posts: 225
Registered: ‎01-17-2012
My Device: PB

Re: BB10 URLStream memory leak

just for fun, tested on my brand new DevAlpha B (16 Gb):

streamFile - httpStatus: 200 bytes loaded: 736024576
streamFile - load complete:
                httpStatus: 200
              httpResponse: null
           response delays:  00:00.102  00:00.105  00:00.114
                   elapsed:  03:24.303
                bytes read: 702 Mb
                 available: avg. 40.7 Kb / max. 2.65 Mb / min. 1.04 Kb
                   pending: avg. 3.34 Mb / max. 4.95 Mb
                read delay:  00:02.257 count: 695 / avg.  00:00.003 / max:  00:00.039
               write delay:  00:21.812 count: 12321 / avg.  00:00.001 / max:  00:00.162
streamFile - buffer closed - delay: 131 (ms)

 this time, lots of throttling needed. (write delay measures how much time we wait because we can't immediately find out bytesPending (need to wait for next outputProgress event)).

 

Since your device only has 1 Gb, I trust you set MaxRead to something a lot smaller than I used... you might also try instrumenting your code to find out min/max bytesAvailable and bytesPending...

 

Regards,

New Developer
luko
Posts: 48
Registered: ‎06-26-2011
My Device: Blackberry Playbook

Re: BB10 URLStream memory leak

 

Again, thanks for help. I really appreciate it.

 

@jtegen

I think that it is something wrong with code because I tried to run this app as standard AIR app on my PC and it doesn't work too.

After downloading about 1GB I got this error:

 

Error: Error #1000: The system is out of memory.
 at flash.net::URLStream/readBytes()

 

strange is that it works fine with my PlayBook.

I can copy file that I couldn't on my PC.

 

 

@mdd

Could You please show me how do You declare bytes variable and do You write downloaded stream to the file.

This is my code for reading and writing of stream after Your suggestions:

 

if (bytesPending > MAX_PENDING)
			{
				readBlocked = true;
				
			}
			else if (_URLStream.connected)
			{
				var _start:uint = _pos_int;
				_pos_int += Math.min(_URLStream.bytesAvailable, MAX_READ);
				
				_bytes = new ByteArray();
				_URLStream.readBytes(_bytes, _start, Math.min(_URLStream.bytesAvailable, MAX_READ));
				
				_fileStream.writeBytes(_bytes, _start);
			}

I think it is something wrong with setting bytearray or offset in readbytes function.

I'm testing it on Dev Alpha A, so it should work the same as on Dev Alpha B.

 

I've been testing bytesAvailable of netstream during copying operation and it is constantly growing (even if I read and write bytes from it).

Developer
Developer
mdd
Posts: 225
Registered: ‎01-17-2012
My Device: PB

Re: BB10 URLStream memory leak

var onProgress:Function = function( e:ProgressEvent ):void
{
	if ( bytesPending > MAX_PENDING )
	{
		readBlocked = true;
	}
	else if ( stream.connected )
	{
		stream.readBytes( bytes, bytes.length, Math.min( stream.bytesAvailable, MAX_READ ) );
					
		if ( bytes.length > 0 )
		{
			streamBuffer.writeBytes( bytes );
                        bytes.clear();
                 }

bytes is a ByteArray, initialized when the request s first sent...

New Developer
luko
Posts: 48
Registered: ‎06-26-2011
My Device: Blackberry Playbook

Re: BB10 URLStream memory leak

[ Edited ]

Thank You mdd.

 

Limitting write buffer and using clear() method to ByteArray helped.