My findings so far...
In addition to PRISM, Unity, WPF and MVVM we are also using Entity Framework and the Xceed data grid. Memory profiling was done using dotTrace.
I ended up implementing IDisposable on a base class for my view models with the Dispose(bool) method being declared virtual allowing sub classes the chance to clean up as well.
As each view model in our application gets a child container from Unity we dispose it as well, in our case this ensure that EF's ObjectContext went out of scope. This was our major source of memory leaks.
The view model is disposed within an explicit CloseView(UserControl) method on a base controller class. It looks for an IDisposable on the DataContext of the view and calls Dispose on it.
The Xceed data grid seems to be causing a fair share of the leaks, especially in long running views. Any view that refreshes the data grid's ItemSource by assiging a new collection should call Clear() on the existing collection before assigning the new one.
Be careful with Entity Framework and avoid any long running object contexts. It's very unforgiving when it comes to large collections, even though you have removed the collection if tracking is turned on, it will hold a reference to every item in the collection even though your no longer hanging on to them.
If you don't need to update the entity retrieve it with MergeOption.NoTracking, especially in long lived views that bind to collections.
Avoid views with a long life, don't hold onto them within a region when they are not visibile, this will cause you grief especially if they refresh their data at regular intervals when they are visible.
When using CellContentTemplates on the Xceed Column don't use dynamic resources as the resource will hold a reference to the cell, which in turn keep the entire view alive.
When using CellEditor on the Xceed Column and the resource is stored in an external resource dictionary add x:Shared="False" to the resource containing the CellEditor, once again the resource will hold a reference to the cell, using x:Shared="False" ensures you get a fresh copy each time, with the old one being removed correctly.
Be careful when binding the DelegateCommand to items within the Exceed data grid, if you have a case such as a delete button on the row which binds to a command, be sure to clear the collection containing the ItemsSource before closing the view. If you're refreshing the collection you also need to reinitialize the command as well as the command will hold a reference to each row.