How to clear UI memory (heap) in WPF page after closing it - memory-management

Here I have a List<DocuemntModel>, where DocumentModel holds property byte[] XpsData.
After converting byte[] XpsData into XPSDocument to bind in <DocumentViewer>.
public static XpsDocument ByteToXpsDocument(byte[] sourceXPS)
{
temp++;
MemoryStream ms = new MemoryStream(sourceXPS);
string memoryName = "memorystream://ms" + temp + ".xps";
Uri memoryUri = new Uri(memoryName);
try
{
PackageStore.RemovePackage(memoryUri);
}
catch (Exception) { }
Package package = Package.Open(ms);
PackageStore.AddPackage(memoryUri, package);
XpsDocument xps = new XpsDocument(package,
CompressionOption.SuperFast, memoryName);
return xps;
}
List<DocumentModel> will load 300+ objects to bind. For each object, it takes 400+kb the size of XPSDocument .
I have successfully done Bindings. But when the page has been loaded the App size increases 300MB . Because of loading all 300+ XPSDocument in page UI.
After I close the current page, the App memory size remains stable. (What I'm expecting is after closing a page it will release all its memory and the App size will get back to its initial size.) and it is not happening.
When I go back and come again to this same page with another 300+ data, the app size increases 500+. App getting slow by slow. Memory is also holding previous data(not required anymore) of this current page.
Now, please read the 5th point again to understand my issue and help me with this.
*My googles
- How to release UI memory in WPF.
- How to clear Heap memory in WPF #.*
Expectation:
The 4th time coming to the same page.xaml, the app size increases to 2400MB and it gets slow and freezes until its loading process completely.
But for the first time, loading does not take a long time (4sec).
What I expect is, For my N time loading the same page will load as like the first time.

Related

Caching Data in Web API

I have the need to cache a collection of objects that is mostly static (might have changes 1x per day) that is avaliable in my ASP.NET Web API OData service. This result set is used across calls (meaning not client call specific) so it needs to be cached at the application level.
I did a bunch of searching on 'caching in Web API' but all of the results were about 'output caching'. That is not what I'm looking for here. I want to cache a 'People' collection to be reused on subsequent calls (might have a sliding expiration).
My question is, since this is still just ASP.NET, do I use traditional Application caching techniques for persisting this collection in memory, or is there something else I need to do? This collection is not directly returned to the user, but rather used as the source behind the scenes for OData queries via API calls. There is no reason for me to go out to the database on every call to get the exact same information on every call. Expiring it hourly should suffice.
Any one know how to properly cache the data in this scenario?
The solution I ended up using involved MemoryCache in the System.Runtime.Caching namespace. Here is the code that ended up working for caching my collection:
//If the data exists in cache, pull it from there, otherwise make a call to database to get the data
ObjectCache cache = MemoryCache.Default;
var peopleData = cache.Get("PeopleData") as List<People>;
if (peopleData != null)
return peopleData ;
peopleData = GetAllPeople();
CacheItemPolicy policy = new CacheItemPolicy {AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(30)};
cache.Add("PeopleData", peopleData, policy);
return peopleData;
Here is another way I found using Lazy<T> to take into account locking and concurrency. Total credit goes to this post: How to deal with costly building operations using MemoryCache?
private IEnumerable<TEntity> GetFromCache<TEntity>(string key, Func<IEnumerable<TEntity>> valueFactory) where TEntity : class
{
ObjectCache cache = MemoryCache.Default;
var newValue = new Lazy<IEnumerable<TEntity>>(valueFactory);
CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(30) };
//The line below returns existing item or adds the new value if it doesn't exist
var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<IEnumerable<TEntity>>;
return (value ?? newValue).Value; // Lazy<T> handles the locking itself
}
Yes, output caching is not what you are looking for. You can cache the data in memory with MemoryCache for example, http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx . However, you will lose that data if the application pool gets recycled. Another option is to use a distributed cache like AppFabric Cache or MemCache to name a few.

Work-around a StackOverflowException

I'm using HtmlAgilityPack to parse roughly 200,000 HTML documents.
I cannot predict the contents of these documents, however one such document causes my application to fail with a StackOverflowException. The document contains this HTML:
<ol>
<li><li><li><li><li><li>...
</ol>
There are roughly 10,000 <li> elements nested like that. Due to the way HtmlAgilityPack parses HTML it causes a StackOverflowException.
Unfortunately a StackOverflowException is not catchable in .NET 2.0 and later.
I did wonder about setting a larger size for the thread's stack, but setting a larger stack size is a hack: it would cause my program to use a lot more memory (my program starts about 50 threads for processing HTML, so all of these threads would have the increased stack size) and would need manually adjusting if it ever came across a similar situation again.
Are there any other workarounds I could employ?
I just patched an error that I believe is the same as your describing. Uploaded the patch to the hap project site...
http://www.codeplex.com/site/users/view/sjdirect (see the patch on 3/8/2012)
Or see more documentation of the issue and result here....
https://code.google.com/p/abot/issues/detail?id=77
The actual fix was...
Added HtmlDocument.OptionMaxNestedChildNodes that can be set to prevent StackOverflowExceptions that are caused by tons of nested tags. It will throw an ApplicationException with message "Document has more than X nested tags. This is likely due to the page not closing tags properly."
How I'm Using Hap After Patch...
HtmlDocument hapDoc = new HtmlDocument();
hapDoc.OptionMaxNestedChildNodes = 5000;//This is what was added
string rawContent = GETTHECONTENTHERE
try
{
hapDoc.LoadHtml(RawContent);
}
catch (Exception e)
{
//Instead of a stackoverflow exception you should end up here now
hapDoc.LoadHtml("");
_logger.Error(e);
}
Ideally, the long-term solution is to patch HtmlAgilityPack to use a heap-stack instead of the call-stack, but that would be an undertaking too big for me. I've temporarily lost my CodePlex account details, but when I get them back I'll submit an Issue report on the problem. I also note that this issue could present a Denial-of-Service attack vulnerability to any site that uses HtmlAgilityPack to sanitize user-submitted HTML - a crafted overly-nested HTML document would cause the w3wp.exe process to die.
In the meantime, I figured the best way forward is to manually override the maximum thread stack size. I was wrong in my earlier statement that a bigger stack-size means that all threads automatically consume that memory (it seems memory pages are allocated for a thread stack as it grows, not all-at-once).
I made a copy of the <ol><li> page and ran some experiments. I found that my program failed when the stack size was less than 2^21 bytes (2MB) in size, but a maximum size of 2^22 bytes (4MB) succeeded - and 4MB in my book passes as an "acceptable" hack... for now.
This should work:
HtmlDocument.MaxDepthLevel = 10000;
var doc = new HtmlDocument();
try
{
doc.LoadHtml(document);
}
catch(Exception ex)
{
Console.WriteLine("Exception while loading html: " + ex);
yield break;
}

In WP7, data is not saved immediately after writing to IsolatedStorage

I encountered this problem while polishing my WP7 application.
Though I follow Microsoft's guidelines to store game state when it's being deactivated, I'd also like to save some data in runtime.
The reason for this is that when the battery is removed from device, no deactivation / closing callbacks are triggered.
The problem with this comes when the user walks through the game and accidentally removes the battery from her device - all game progress is lost.
That's why I do save game state at some intermediate checkpoints, but I have noticed that data is not stored immediately. This is my "save" function:
public void SaveAppModelToIsolatedStorage()
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = new IsolatedStorageFileStream(APPMODEL_DATAFILE,
FileMode.Create,
FileAccess.Write,
store))
{
var serializer = new XmlSerializer(typeof(AppModel));
try
{
serializer.Serialize(stream, AppModel);
}
catch (Exception ex)
{
Debug.WriteLine("Cant serialize AppModel:" + ex.Message);
}
}
}
After it's been called, if I remove the battery within a number of seconds (not sure how many but always less than 30), the application ends up with lost game progress. If I wait before removing battery, the data would be saved successfully. This behavior is observed on various WP7 phones.
I also tried serialization into a string buffer and then writing that string buffer to the file by calling stream.Write(), but the result is the same. Also, stream.Flush() doesn't seem to have an effect.
Is this behavior a platform feature?
Is it fine in terms of Microsoft certification for Marketplace apps?
Or is there a way to save data immediately?
Just call stream.Close when you need flush your data.
Also, try calling stream.Flush(true);
This may be interesting regarding performance of Isolated Storage : forums.create.msdn.com/forums/p/71708/71708.aspx

Get rid of invisible UltraGridRow instances

I've got a grid that show tens of thousands of rows in total, obviously the user is only looking at a small fraction of those rows at any point in time, generally somewhere around 10~20 rows.
I enabled LoadOnDemand, which ensures that UltraGridRow instances and a couple of other objects will only be created when they move into the visible area:
grid.DisplayLayout.LoadStyle = LoadStyle.LoadOnDemand;
This works great (according to my memory profiler), but when I scroll up and down the whole table, i.e. trigger creation of UltraGridRows for all rows, then all UltraGridRows will get created and stay in memory forever.
How can I (ideally automatically, but if not, manually) get rid off the UltraGridRow objects for rows that are out of view? (Or just get rid of all UltraGridRows - they'll be recreated automatically anyway)
One brute force way I figured out is this:
var tmp = grid.DataSource;
grid.DataSource = null;
grid.DataSource = tmp;
It causes some side effects though, so is there some other way to get rid of UltraGridRows?
Btw, I tried these two guys, without success (trying true and false for the bool params).
grid.Rows.Refresh(RefreshRow.ReloadData, false, true);
grid.Rows.DeallocateCells(true);
I'm trying to get memory consumption down, and UltraGridRows are currently the main consumer (UltraGridRows by themselves aren't huuuge, they consume under 200 bytes each, which in my case means a couple of megabytes, just so you know what we are talking about).
This is Infragistics 9.2.
Any ideas?
Well, there's always reflection...
var m = typeof(RowsCollection)
.GetMethod("InternalClearHelper", BindingFlags.NonPublic | BindingFlags.Instance);
m.Invoke(grid.Rows, null);
This actually works for me, but it will clear the selection, so you have to remember that before invoking and restore the selection afterwards.

Selenium Firefox Open timeout

Using Windows 2008, C#, Firefox 3.5.1, Selenium RC (v1.0.1)
When it works, this code executes very quickly and the page loads within .5 seconds.
However, the session always seems to fail after 3 - 5 iterations. The open command will cause a window to be spawned, but no page to be loaded. Eventually a timeout exception is returned. The page has not actually timed out. Instead, it is as though the request for a URL has never reached the browser window.
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
var s = new DefaultSelenium("localhost", 4444, "firefox", "http://my.server");
s.Start();
s.SetSpeed("300");
s.Open("/");
s.WaitForPageToLoad("30000");
s.Type("//input[contains(#id, '_username')]", "my.test");
s.Type("//input[contains(#id, '_password')]", "password");
s.Stop();
}
}
}
I have a similar set up (Firefox 3.6.15, Selenium RC 1.0.1, but on WinXP and using the Python libraries) and I am working with a couple of sites - one site is naturally prone to timeouts in normal use (e.g. by a human user) whereas the others typically are not. Those that aren't appear a little slower but the one that is prone to timeouts is significantly slower when run via RC than by a person - it won't always timeout but the incidence is much much more common.
My limited mental model for this is that somehow the extra steps RC is doing (communicating with the browser, checking what it sees in the returned pages etc etc) are somehow adding a bit to each step of the page loads and then at some point they will push it over the edge. Obviously this is overly simplified, I just haven't had time to properly investigate.
Also, I do tend to notice that the problem gets worse over time, which fits a little with what the OP has seen (i.e. working the first time but not after 3 - 5 attempts). Often a reboot seems to fix the issues, but without proper investigation I can't tell why this helps, perhaps it is somehow freeing up memory (the machine is used for other things), getting allocated to a different one of our company's proxies or something else I haven't considered.
So... not much of a full answer here (a comment would have been more appropriate, but my login isn't able to yet), but at least it reinforces that you're not the only one. Periodic restarts are an annoying thing to need to do, but in the absence of any smarter analysis and answers, maybe they'd be worth a shot?
I was facing the same problem .This is because open method of DefaultSelenium has timeout of 30000ms, so it waits for 30s for your page to load. You can try this trivial solution.
//selenium is DefaultSelenium instance as private member of the class
boolean serverStartTry = false;
int tryCount =1;
while((!serverStartTry) && tryCount <= Constants.maxServerTries){
try{
this.selenium.open(ReadConFile.readcoFile("pageName"));
System.out.println("Server started in try no: "+tryCount);
serverStartTry =true;
}catch (SeleniumException e) {
System.out.println("Server start try no: "+tryCount );
System.out.println("Server Start Try: "+ serverStartTry);
serverStartTry = false;
tryCount++;
}
}
if(!serverStartTry){
System.out.println("Server Not started, no. of attempts made: "+tryCount);
System.exit(0);
}
I've solved using:
selenium.setTimeout("60000");
before open instruction.

Resources