I am building a small Windows Phone 8 app (a Christian-Orthodox calendar) which has a background agent which should update the live tile. The app will require access to the contacts in the phone so I opted out of internet access so backend tile generation is, at least now out of question. I personally would not trust an app that has access to my contacts AND to internet.
Recently my scheduled agent (which generates three PNGs) started OutOfMemoryException-ing on me. Consistently. I've used DeviceStatus to query and debug its behavior.
It's hard to call this a memory leak since between all three tile generations if I call GC.Collect it won't throw OutOfMemoryException. If it were a true memory leak some (large and/or many) objects would remain referenced by other live/root objects and no amount of GC.Collect will help. In my case GC.Collect WILL help. I can continue using GC.Collect but I feel dirty doing so.
As I'm developing the app free and open-source you can view in detail all the code of the project at the current state of development at http://orthodoxcalendar.codeplex.com
The tile generation consists of taking a background and overlaying two other images on that background. Basically for each of the three PNGs generated I do
var bytes1 = (byte[])resourceManager.GetObject(resourceName1);
var stream1 = new MemoryStream(bytes);
var bytes2 = (byte[])resourceManager.GetObject(resourceName2);
var stream2 = new MemoryStream(bytes);
var bytes3 = (byte[])resourceManager.GetObject(resourceName3);
var stream3 = new MemoryStream(bytes);
var writeableBitmap1 = BitmapFactory.New(size.Width, size.Height).FromStream(stream1); // background
var writeableBitmap2 = BitmapFactory.New(size.Width, size.Height).FromStream(stream2); // first overlay
var writeableBitmap3 = BitmapFactory.New(size.Width, size.Height).FromStream(stream3); // second overlay
writeableBitmap1.Blit(new Point(0, 0), writeableBitmap2, new Rect(0, 0, width2, height2), Colors.White, BlendMode.Alpha);
writeableBitmap1.Blit(new Point(0, 0), writeableBitmap3, new Rect(0, 0, width3, height3), Colors.White, BlendMode.Alpha);
writeableBitmap1.DrawText("Some text", new Point(5, 139), Color.Black, 17);
writeableBitmap1.Invalidate(); // flatten things
using(var outputStream = new WhateverStream())
{
PNGWriter.Write(writeableBitmap1, outputStream);
}
writeableBitmap1.SetSource(new MemoryStream(MiscData.MinimumPng)); // set the writeable bitmap to a 1x1 transparent PNG to, hopefully, force it to release unamanaged memory or other stuff
writeableBitmap2.SetSource(new MemoryStream(MiscData.MinimumPng));
writeableBitmap3.SetSource(new MemoryStream(MiscData.MinimumPng));
stream1.Dispose();
stream2.Dispose();
stream3.Dispose();
The code, if you'll check out the project, is not exactly like above since I've wrapped almost all dependencies in adapters and extracted interfaces. Across many assemblies. The above code is the simplified version which just shows, what I consider to be, the relevant code lines.
A few explanations for the code above :
all this code is run in the background agent inside a Dispatcher.BeginInvoke since you can't seem to manipulate a WritableBitmap on any other thread than the UI thread
The PNG data is stored in another assembly as resx. I know this fattens the assembly but I need this to reuse it across platforms as the assembly is a PCL
Creating the WriteableBitmap directly using a byte array seems to fail in a mysterious way so I'm wrapping it in a MemoryStream and somehow, this way, it works
The PNG writer is taken from ToolStack.
It's not feasible to pre-generate the images since there are multiple versions of "first overlay", "second overlay" and, mostly the "Some text". It would mean tens of thousands of images, at least.
The heart of the question : Am I doing something awfully wrong that I'm not aware of? The only thing that pops in my mind is that JPEGs are generated faster and with less memory consumption but they won't have transparency which I desire. Can this be actually called a memory leak?
LATER EDIT : It seems that after some more debugging it changed its behavior from the one above to a true memory leak. I switched from PNG generation to JPEG generation and the memory is lower now. The input images are still PNG but at the other end a JPEG will be spit. The memory footprint went several megabytes below the previous threshold(s).
SECOND EDIT : I put the logic in a 10.000 repeat loop on a button and there doesn't seem too much memory consumption. I am beginning to think that there isn't really a memory leak but just higher memory consumption during the generation and that's enough to bring the fragile agent down.
In doing a similar thing I've had to explicitly set the writeablebitmaps to null (even though should be unnecessary) before calling GC.Collect.
Additionally, it may be better to create and destroy (and collect) each of the images in turn, rather than creating them all and then destroying them all. This will help with the overhead at any one point.
Also note that when tracking the memory use in the debugger, the debugger adds about 3mb of overhead that you won't see when live.
Related
I'm using Puppeteer (PuppeteerSharp actually, but the API is the same) to take a screenshot of a web page from my application.
The problem is that the page does several layout changes via JavaScript after the page has loaded, so a few seconds pass before seeing the "final" rendered version of the page.
At the moment I'm just waiting a "safe" amount of seconds before taking the screenshot, but this is obviously not a good approach, since a temporary performance slowdown on the machine can result in an incomplete rendering.
Since puppeteer uses Chromium in the background, is there a way to intercept Chromium's layouting/rendering events (like you can do in the DevTools console in Chrome)? Or, really, ANY other way to know when the page has stopped "changing" (visually I mean)
EDIT, some more info: The content is dynamic, so I don't know before hand what it will draw and how. Basically, it's a framework that draws different charts/tables/images/etc. (not open-source unfortunately). By testing with the "performance" tool in the Chrome DevTools however, I noticed that after the page has finished rendering all activity in the timeline stops, so if I could access that information it would be great. Unfortunately, the only way to do that in Puppeteer (that I can see) is using the "Tracing" feature, but that doesn't operate in real-time. Instead, it dumps the trace to file and the buffer is way too big to be of any use (the file is still 0 bytes after my page has already finished rendering, it only flushes to disk when I call "stopTracing"). What I would need is to access the Tracing feature of puppeteer in realt-time, for example via events or a in-memory stream, but that doesn't seem to be supported by the API. Any way around this?
You should use page.waitForSelector() to wait for the dynamic elements to finish rendering.
There must be a pattern that can be identified in terms of the content being generated.
Keep in mind that you can use flexible CSS Selectors to match elements or attributes without knowing their exact values.
await page.goto( 'https://example.com/', { 'waitUntil' : 'networkidle0' } );
await Promise.all([
page.waitForSelector( '[class^="chart-"]' ), // Class begins with 'chart-'
page.waitForSelector( '[name$="-image"]' ), // Name ends with '-image'
page.waitForSelector( 'table:nth-of-type(5)' ) // Fifth table
]);
This can be useful when waiting for a certain pattern to exist in the DOM.
If page.waitForSelector() is not powerful enough to meet your needs, you can use page.waitForXPath():
await page.waitForXPath( '//div[contains(text(), "complete")]' ); // Div contains 'complete'
Alternatively, you can plug the MutationObserver interface into page.evaluate() to watch for changes being made to the DOM tree. When the changes have stopped over a period of time, you can resume your program.
After some trial and error, I settled for this solution:
string traceFile = IOHelper.GetTemporaryFile("txt");
long lastSize = 0;
int cyclesWithoutTraceActivity = 0;
int totalCycles = 0;
while (cyclesWithoutTraceActivity < 4 && totalCycles < 25)
{
File.Create(traceFile).Close();
await page.Tracing.StartAsync(new TracingOptions()
{
Categories = new List<string>() { "devtools.timeline" },
Path = traceFile,
});
Thread.Sleep(500);
await page.Tracing.StopAsync();
long curSize = new FileInfo(traceFile).Length;
if(Math.Abs(lastSize - curSize) > 5)
{
logger.Debug("Trace activity detected, waiting...");
cyclesWithoutTraceActivity = 0;
}
else
{
logger.Debug("No trace activity detected, increasing idle counter...");
cyclesWithoutTraceActivity++;
}
lastSize = curSize;
totalCycles++;
}
File.Delete(traceFile);
if(totalCycles == 25)
{
logger.Warn($"WARNING: page did not stabilize within allotted time limit (15 seconds). Rendering page in current state, might be incomplete");
}
Basically what I do here is this: I run Chromium's tracing at 500 msec intervals, and each time I compare the size of the last trace file to the size of the current trace file. Any significant changes in the size are interpreted as activity on the timeline, and they reset the idle counter. If enough time passes without significant changes, I assume the page has finished rendering. Note that the trace file always starts with some debugging info (even if the timeline itself has no activity to report), this is the reason why I don't do an exact size comparison, but instead I check if the file's lengths are more than 5 bytes apart: since the initial debug info contains some counters and IDs that vary over time, I allow for a little variance to account for this.
I'am doing a Qt app in c++ with frontend in Html / Css.
Each time i load a new html page (or if i reload one), the app get +5mo ram, and dont get free after quit. (So after 10 pages i got +50mo ram)
I've allready try to préload my pages into a vector, but the loading still add 5mo each time.
I've also think to load pages in threads, so they'll be destroyed after using.
Is it a possible solution to keep a descent ram weight??
As i'am a newbie i'am probably doing something stupid : here's my code for loading a new view :
Q_INVOKABLE bool myBridge::newView(QString page)
{
QString path = ("file:///" + QDir::currentPath() + "/");
if (!(page.compare("page3.html")))
_mediaPlayer->setTimer(10000);
else
_mediaPlayer->setTimer(60000);
_view->close();
_view = new WebView;
_view->load(QUrl(path + page));
_view->page()->mainFrame()->addToJavaScriptWindowObject("bridge", this);
_view->showFullScreen();
_mediaPlayer->_srnsaver->timerRestart();
return (true);
}
Can you see something wrong in this code?
Every time this method is called you create a new WebView and you most likely never delete the previous one. Naturally this will cause a memory leak since nothing is freed. Calling close() does not delete the object.
I created a batch of sounds assembled with this tool:
AudioSprite
https://github.com/tonistiigi/audiosprite
The output is generally used for JS libraries, such as Howler, Zynga Jukebox, or SoundJS - but I wanted to see if it's possible to implement in AS3.
I started creating a Sound player that can load, parse and play the sounds based on the JSON and MP3 file this tool generates.
So far so good! ... except for loops.
Now, the big question is - is there a way to play a Sound-loop seamlessly given that all music & sounds coexist in the same MP3 file, and it has a start & end range to play and stop it?
Example of how the sounds are placed in the file:
mygame_sounds.mp3 = [BUZZ + LASER + BOING ... + TRACKLOOP]
I'm looking for a solution that does not involve using the SAMPLE_DATA Event (given it eats up a lot of CPU usage). If there's no way around it, please explain why.
So far I've had mild success using flash.utils.Timer objects triggered after a given AudioSprite's duration, but it's not consistent.
To stop / dispose of a non-looping sound, I rely on a Master Timer (running at very short intervals) and that seems to "cut" the sample appropriately. But I already tried using this Master Timer to play a looped-sound over and over - same latency issues.
Is there any method to predict / measure how much latency is to be expected by the time the sound completes one pass?
In SoundJS we could not find a way to allow smooth looping of audio sprites in AS3 and went with a timer. We found Web Audio was the only api that allowed smooth looping, and therefore recommended staying away from audiosprites for sounds that needed to loop smoothly if any other plugin might be used.
Hope that helps.
The reason of why you can't get smooth loops of a track retrieved from a larger audio file is that you cannot check sound position faster than once per SWF frame, which length depends on stage.frameRate and total processing time of your application and is generally varied. So, if your looping sounds lasts say 5.123 seconds (I don't care how many samples, just that its length does not make a full number of frames regardless of stage.frameRate), your sound will attempt to play for either 5.125 seconds (205 frames at 40 fps, IMO best bet for this particular sound), 5.133 seconds (154 frames at 30 fps) or some weird number of frames if the SWF would experience lag. The excess milliseconds cannot be totally controlled by any means due to AS3/Flash engine optimization. So, consider not using audio sprites and shift into audio packs (several audio files in an SWF, or one sound in an MP3).
Although I'm still working on the perfect solution, this is the best I could come up with:
Load the JSON file / ByteArray.
Parse the JSON file to obtain each sprites' ID, start and end times.
Load the MP3 file / ByteArray (requires loadCompressedDataFromByteArray()) into a master Sound object.
Once loaded, check if any sprites are marked as "loops".
Create separate Sound objects for the above loops, and extract the portion from the master Sound via loadPCMFromByteArray() with some "magic-numbers" (details below).
To play a one-shot sound, call the master Sound's play(sprite.start * 1000) (depending on the format, usually the JSON's start values are in seconds, needs to be in milliseconds).
To play a seamless-loop sound, call the individual Sound object's (created in step #5) play(0, 9999) method.
I won't go too deep in details on how to stop the sounds (SoundChannel.stop(), bam!), but I'll explain the "magic-numbers" mentioned above. See this snippet:
var goldenOffset:UInt = (64 << 5);
var goldenDuration:UInt = (64 << 2);
var sampleRate:UInt = 44100;
for (id in loops) {
var sprite:AudioSpriteItem = _mapSprites.get(id);
var loop:Sound = _mapLoops.get(id);
var sampleBytes = new ByteArray();
var samplesTotal:UInt = cast(sprite.duration * sampleRate + goldenDuration);
var samplesStart:UInt = cast(sprite.start * sampleRate + goldenOffset);
_sound.extract(sampleBytes, samplesTotal, samplesStart);
sampleBytes.position = 0;
loop.loadPCMFromByteArray(sampleBytes, samplesTotal, "float", true);
}
Quite honestly, these magic goldenOffset and goldenDuration values were just found via Trial-and-Error. I could get close to a seamless loop without them by just calculating the start and duration with the sampleRate (assuming 44100 by default), but each endings had a bit of a hiccup to it.
After several adjustments, those couple "64 left bit-shifted" values made the loops sound smoother.
I posted the Haxe project on github (compiled SWC also available in /bin folder) if you wish to try it / read through the code.
FLAudioSprite
Github page: https://github.com/bigp/FLAudioSprite
SWF Demo (Download): bit.ly/FLAudioSpriteSWFDemo
I have an Mvx base iOS project which is having problems with image downloads.
I have a couple of screens which contain UICollectionViews and the UICollectionViewCells use MvxDynamicImageHelpers to set the Image of their UIImageViews to images hosted on the internet (Azure blob storage via Azure CDN in actual fact). I have noticed that the images sometimes do not appear and that this is more common on a slow connection and if I scroll through the whole UICollectionView while the images are loading - presumably as it initiates a large number of simultaneous downloads. Restarting the app causes some, but not all, of the images to be shown.
Looking in the Caches/Pictures.MvvmCross folder I see there are a number of files with .tmp extensions and some without .tmp extensions but a 0 byte file size. I presume that the .tmp files are the ones that are re-downloaded following an app restart and that an invalid in-memory cache entry is causing them not to be re-downloaded until this happens.
I have implemented my versions of MvxDownloadRequest and MvxHttpFileDownloader and registered my IMvxHttpFileDownloader. The only modification in MvxHttpFileDownloader is to use my MvxDownloadRequest instead of the standard Mvx one.
As far as I can see, there are no exceptions being thrown in MvxDownloadRequest.Start or MvxDownloadRequest.ProcessResponse and MvxDownloadRequest.FileDownloadFailed is not being called. Having replaced MvxDownloadRequest.Start with the following, all images are always downloaded and displayed successfully:
try
{
ThreadPool.QueueUserWorkItem((state) => {
try
{
var fileService = this.GetService<IMvxSimpleFileStoreService>();
var tempFilePath = DownloadPath + ".tmp";
var imageData = NSData.FromUrl(NSUrl.FromString(Url));
var image = UIImage.LoadFromData(imageData);
NSError nsError;
image.AsPNG().Save(tempFilePath, true, out nsError);
fileService.TryMove(tempFilePath, DownloadPath, true);
}
catch (Exception exception)
{
FireDownloadFailed(exception);
return;
}
FireDownloadComplete();
});
}
catch (Exception e)
{
FireDownloadFailed(e);
}
So, what could be causing the problems with the standard WebRequest which is not affecting the above version? I'm guessing it's something to with GC and will do further debugging when I get time, but this won't be fore a while unfortunately. Would be very much appreciated if someone can answer this or provide pointers for when I do look at it.
Thanks,
J
From the description of your investigations so far, it sounds like you have isolated the problem down to the level that httpwebrequest sometimes fails, but that the NSData methods are 100% reliable.
If this is the case, then it would suggest that the problem is somewhere in the xamarin.ios network stack or in the use of it.
It might be worth checking the xamarin bugzilla repository and also asking their support team if they are aware of any issues in this area. I believe they did make some announcements about changes to the iOS networking at evolve - see the CFNetworkHandler part late in the video and slides at http://xamarin.com/evolve/2013#session-b3mx6e6rmb - and there are worrying questions on here like iPhone app gets into a state where network requests never complete
Beyond that, I'd guess the first step in any debugging would be to isolate the issue in a simple test app - eg a simple app which just downloads one image at a time and which demonstrates a simple pass/fail for each technique. If you can replicate the issue in a small test app, then it'll be much quicker to work out what the issue is.
I have an AS3 application that loads various SWFs at runtime. The loading animation that is being used has a fairly long in and out animation that I don't want to show if the target SWF is in the browser cache.
So at the moment each SWF is loaded in as required using Greensock's SWFLoader in a basic manner:
var context:LoaderContext = new LoaderContext();
context.applicationDomain = ApplicationDomain.currentDomain;
loader = new SWFLoader("mySWF.swf", {name:"sectionLoader",context:context,auditSize:true,onOpen:onLoadInit,onProgress:onLoadProgress, onComplete:onCompleteLoadHandler, onError:onLoadErrorHandler});
loader.load();
My goal is to do something before calling loader.load(); to determine if the load operation will require the request to go beyond the browser cache, but before I get into R&Ding something I thought I'd ask if anyone has already done something similar.
A few more thoughts I've had so far:
Just keeping track of what has been loaded in AS3 isn't good enough because if the user clears their cache they might be left loading a large SWF on a slow connection with no indicator.
Might a combination of LoaderItem.httpStatus and LoaderItem.auditSize() be worth investigating?
Is there a better loading framework for AS3 that I should be looking into instead of the Greensock classes?
Ideally I would prefer to also have some kind of version detection to span sessions that could be months apart, but one step at a time.
when you are doing any HTTP request, the responce comes up with HTTPStatus property. In AS3 you just need to chek if
HttpStatusEvent.status == 304
And for httpStatus in greensock library.
Basically 304 code means that no chages has been made on server side to the resource which user has requested. Which eventually leads to conclution that the resource is in the cache.
UPDATE
If this will not fit your needs try storing some variable for should you play the animation or not in Cookies or in Session variables.