Geeks With Blogs

News Hi, my name is Vincent Grondin and I'm a senior consultant at Fujitsu, a consulting firm in Montreal, Québec. I'm starting that blog to share some of my thoughts and knowledge on .NET architectures and code. Being a consultant in the .NET world I come across many different things. Some good, some bad and others that are worth a blog post here whether they be good, or hmmm... shall I say, less good :) I hope you enjoy yourself while learning new stuff. Feel free to leave a comment or contact me anytime.
Vincent Grondin

 

So our WPF app that we’ve been building for the past 18 months had memory leaks and we needed to find and fix them. I’m not going to talk about how to find them (aside from mentioning you should get a good 3rd party memory profiler tool) and will focus on a rule we ended up checking throughout our entire application to avoid memory leaks. First off I want to tell everyone that this had nothing to do with simple references not released or a cache that wasn’t cleared or anything like such… This was entirely WPF related and maybe some of you WPF gurus would have found this fast but it wasn’t so obvious to us what we were doing wrong. Apparently this is a known situation at MS and by design, so instead of saying it’s a bug, we’ll be politically correct and say it’s a “feature”. Smile

So to avoid wrongfully using that “feature” whenever you create a binding whether via XAML or by code (C# or VB.NET) you must fulfill at least 1 of those 3 conditions:

- The binding target must implement INotifyPropertyChanged

- The target property must be a Dependency Property

- The binding mode is OneTime

If you fail to comply with all 3 rules (meaning not at least 1 is followed), then the “feature” will be “activated” and I’m pretty sure you need that “feature” active as much as you need to have a tooth pulled without anesthesia. I did a little humor there with the feature thing but really it’s something that could bite you big time if you do not pay attention to it… We ended up building a tool that would tell us if there are bindings that do not match this rule. The tool is activated by a key combo in our application and sends the binding information to the clipboard for the devs to checkout. The best thing would have been a custom Code Analysis Rule that would generate a compile time error but we didn’t have time for this…

Here’s the code and it’s coming from the web…

Thanks to my co-workers Francois Cantin and Gabriel Létourneau at Fujitsu for digging and finding this stuff Smile

Happy coding all.

 

private static void GetReflectPropertyDescriptorInfo()

{

List<ReflectPropertyDescriptorInfo> listInfo = new List<ReflectPropertyDescriptorInfo>();

// get the ReflectTypeDescriptionProvider._propertyCache field

Type typeRtdp = typeof(PropertyDescriptor).Module.

GetType("System.ComponentModel.ReflectTypeDescriptionProvider");

FieldInfo propertyCacheFieldInfo = typeRtdp.GetField("_propertyCache",

BindingFlags.Static | BindingFlags.NonPublic);

Hashtable propertyCache = (Hashtable)propertyCacheFieldInfo.GetValue(null);

if (propertyCache != null)

{

// try to make a copy of the hashtable as quickly as possible (this object can be accessed by other threads)

DictionaryEntry[] entries = new DictionaryEntry[propertyCache.Count];

propertyCache.CopyTo(entries, 0);

FieldInfo valueChangedHandlersFieldInfo = typeof(PropertyDescriptor).GetField("valueChangedHandlers",

BindingFlags.Instance | BindingFlags.NonPublic);

// count the "value changed" handlers for each type

foreach (DictionaryEntry entry in entries)

{

PropertyDescriptor[] pds = (PropertyDescriptor[])entry.Value;

if (pds != null)

{

foreach (PropertyDescriptor pd in pds)

{

Hashtable valueChangedHandlers = (Hashtable)valueChangedHandlersFieldInfo.GetValue(pd);

if (valueChangedHandlers != null && valueChangedHandlers.Count != 0)

listInfo.Add(new ReflectPropertyDescriptorInfo(entry.Key.ToString(), pd.Name,

valueChangedHandlers.Count));

}

}

}

}

listInfo.Sort();

Clipboard.SetText(string.Join(Environment.NewLine, listInfo.Select(i => string.Format("{0} - {1}", i.TypeName, i.PropertyName))));

}

public sealed class ReflectPropertyDescriptorInfo : IComparable<ReflectPropertyDescriptorInfo>

{

public ReflectPropertyDescriptorInfo(string typeName, string propertyName, int handlerCount)

{

m_typeName = typeName;

m_propertyName = propertyName;

m_handlerCount = handlerCount;

}

public string TypeName

{

get { return m_typeName; }

}

public string PropertyName

{

get { return m_propertyName; }

}

public int HandlerCount

{

get { return m_handlerCount; }

}

public string DisplayHandlerCount

{

get

{

return m_handlerCount == 1 ? "" : string.Format(CultureInfo.InvariantCulture,

" ({0:n0} handlers)", m_handlerCount);

}

}

public int CompareTo(ReflectPropertyDescriptorInfo other)

{

if (object.ReferenceEquals(other, null))

return 1;

int compareResult = m_typeName.CompareTo(other.m_typeName);

if (compareResult == 0)

compareResult = m_propertyName.CompareTo(other.m_propertyName);

if (compareResult == 0)

compareResult = m_handlerCount.CompareTo(other.m_handlerCount);

return compareResult;

}

readonly string m_typeName;

readonly string m_propertyName;

readonly int m_handlerCount;

}

Posted on Monday, April 28, 2014 10:05 PM | Back to top


Comments on this post: Are your WPF Apps leaking memory? Maybe it’s a feature of WPF!

# re: Are your WPF Apps leaking memory? Maybe it’s a feature of WPF!
Requesting Gravatar...
Wow ! I have read many articles about WPF and it's the first time I hear about this "features". Thanks, good to know !
Left by Laurent on Aug 31, 2014 1:22 PM

Your comment:
 (will show your gravatar)


Copyright © Vincent Grondin | Powered by: GeeksWithBlogs.net