背景
我们应用程序中最常用的数据结构之一是自定义 Point 结构。最近我们遇到了内存问题,主要是由于该结构的实例数量过多引起的。
其中许多实例包含相同的数据。共享单个实例将大大有助于减少内存使用。但是,由于我们使用的是结构,因此不能共享实例。也不可能将其更改为类,因为结构语义很重要。
我们的解决方法是使用一个包含对包含实际数据的支持类的单个引用的结构。这些享元数据类存储在工厂中并从工厂中检索,以确保不存在重复项。
代码的缩小版本如下所示:
public struct PointD
{
//Factory
private static class PointDatabase
{
private static readonly Dictionary<PointData, PointData> _data = new Dictionary<PointData, PointData>();
public static PointData Get(double x, double y)
{
var key = new PointData(x, y);
if (!_data.ContainsKey(key))
_data.Add(key, key);
return _data[key];
}
}
//Flyweight data
private class PointData
{
private double pX;
private double pY;
public PointData(double x, double y)
{
pX = x;
pY = y;
}
public double X
{
get { return pX; }
}
public double Y
{
get { return pY; }
}
public override bool Equals(object obj)
{
var other = obj as PointData;
if (other == null)
return false;
return other.X == this.X && other.Y == this.Y;
}
public override int GetHashCode()
{
return X.GetHashCode() * Y.GetHashCode();
}
}
//Public struct
public Point(double x, double y)
{
_data = Point3DDatabase.Get(x, y);
}
public double X
{
get { return _data == null ? 0 : _data.X; }
set { _data = PointDatabase.Get(value, Y); }
}
public double Y
{
get { return _data == null ? 0 : _data.Y; }
set { _data = PointDatabase.Get(X, value); }
}
}
此实现确保维护结构语义,同时确保仅保留相同数据的一个实例。
(请不要提及内存泄漏等,这是简化的示例代码)
问题
尽管上述方法可以降低我们的内存使用量,但性能非常糟糕。我们应用程序中的一个项目很容易包含一百万个或更多不同的点。因此,查找PointData
实例的成本非常高。每次操作 a 时都必须进行这种查找Point
,正如您可能猜到的那样,这就是我们的应用程序的全部内容。因此,这种方法不适合我们。
作为替代方案,我们可以制作Point
该类的两个版本:一个具有上述支持享元,另一个包含它自己的数据(可能有重复)。所有(短期)计算都可以在第二类中完成,而当存储Point
更长的持续时间时,它们可以转换为第一类,节省内存。但是,这意味着Point
必须检查该类的所有用户并根据该方案进行调整,这对我们来说是不可行的。
我们正在寻找的是一种满足以下标准的方法:
- 当有多个
Point
具有相同数据的 s 时,内存使用量应该低于每个具有不同结构实例的内存使用量。 - 性能应该不会比直接处理结构中的原始数据差多少。
- 应该维护结构语义。
- 'Point' 接口应该保持不变(即使用'Point' 的类不应该改变)。
有什么方法可以改进我们对这些标准的处理方法吗?或者任何人都可以提出我们可以尝试的不同方法吗?