|
I was profiling my application and noticed that a fair amount of time is spent during Map initialization creating the Known Coordinate Systems. Every known coordinate system is created. This also increases the memory used by the application. Some
applications may require DotSpatial.Projections.dll but may not need KnownCoordinateSystems. I played around a bit with varying degrees of just-in-time creation. I tried 2 approaches, both of which appeared to work. I outline them
below. I would like to propose we at least implement the 1st approach since it is a simple change. If the 2nd approach is used, the 1st approach is not needed.
Approach 1:
. I made a simple change to the static class KnownCoordinateSystems from this:
public static class KnownCoordinateSystems
{
/// <summary>
/// Geographic systems operate in angular units, but can use different
/// spheroid definitions or angular offsets.
/// </summary>
public static GeographicSystems Geographic = new GeographicSystems();
/// <summary>
/// Projected systems are systems that use linear units like meters or feet
/// rather than angular units like degrees or radians
/// </summary>
public static ProjectedSystems Projected = new ProjectedSystems();
}
to this:
public static class KnownCoordinateSystems
{
private static GeographicSystems _geographic;
private static ProjectedSystems _projected;
/// <summary>
/// Projected systems are systems that use linear units like meters or feet
/// rather than angular units like degrees or radians
/// </summary>
public static ProjectedSystems Projected
{
get { return _projected ?? (_projected = new ProjectedSystems()); }
}
/// <summary>
/// Geographic systems operate in angular units, but can use different
/// spheroid definitions or angular offsets.
/// </summary>
public static GeographicSystems Geographic
{
get { return _geographic ?? (_geographic = new GeographicSystems()); }
}
}
This change delays any creation of the Projected or Geographic systems until they are actually accessed. This speeds up initialization of any applications that don't care about KnownCoordinateSystems. But, once an application accesses either Projected or Geographic, all categories (and their child coordinate systems) are at that point created, thus using memory for many many unused coordinate systems.
2. The next thing I tried was just-in-time creation of categories in the ProjectedSystems and GeographicSystems classes. This was a little more work, but appeared to work. I won't show all the changes, but here are the representative ones:
The old code was:
namespace DotSpatial.Projections
{
/// <summary>
/// Projected
/// </summary>
public class ProjectedSystems
{
private string[] _names;
#region Fields
public readonly Africa Africa;
// and so on...
public ProjectedSystems()
{
Africa = new Africa();
// and so on...
}
private void AddNames()
{
FieldInfo[] flds = GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
_names = new string[flds.Length];
for (int i = 0; i < flds.Length; i++)
{
_names[i] = flds[i].Name;
}
}
/// <summary>
/// Given the string name, this will return the specified coordinate category
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public CoordinateSystemCategory GetCategory(string name)
{
FieldInfo[] flds = GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < flds.Length; i++)
{
if (flds[i].Name == name)
{
return flds[i].GetValue(this) as CoordinateSystemCategory;
}
}
return null;
}
}
}
The new code is:
namespace DotSpatial.Projections
{
/// <summary>
/// Projected
/// </summary>
public class ProjectedSystems
{
private string[] _names;
#region Fields
private Africa _africa;
// and so on...
public Africa Africa
{
get { return _africa ?? (_africa = new Africa()); }
}
// and so on...
private void AddNames()
{
PropertyInfo[] properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
_names = (from property in properties where property.Name != "Names" select property.Name).ToArray();
}
public CoordinateSystemCategory GetCategory(string name)
{
PropertyInfo property = GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
if (null == property)
return null;
return property.GetValue(this, null) as CoordinateSystemCategory;
}
}
}
With this 2nd approach, a category is created just-in-time, thus only requiring memory for the child coordinate systems in that category. However, I had to change the way we use Reflection to get the Names and Categories from using FieldInfo to PropertyInfo. This could be taken even further to just-in-time creation of individual coordinate systems in a category, but that would be much more tedious.
|