我有一个应用程序,出于性能原因在内存中保存了大量实例,我不想要将其写入磁盘或任何其他地方,只需将其全部保存在内存中
public class MyObject
{
public string Name;
public object Tag;
public DateTime DateTime1;
public DateTime DateTime2;
public DateTime DateTime3;
public long Num1;
public uint Num2;
public uint Num3;
public ushort Num4;
}
在许多情况下,我实际上并没有使用所有字段,或者没有充分利用字段的整体大小。所以我想也许可以将整个类转换为具有属性的接口,并使许多实现类以不同的方式存储数据:使用较小的字段(例如int而不是long)并省略一些未使用的字段。
示例:
public interface IMyObject
{
string Name { get; set; }
object Tag { get; set; }
DateTime DateTime1 { get; set; }
DateTime DateTime2 { get; set; }
DateTime DateTime3 { get; set; }
long Num1 { get; set; }
uint Num2 { get; set; }
uint Num3 { get; set; }
ushort Num4 { get; set; }
}
public class MyObject1 : IMyObject
{
public string Name { get; set; }
public object Tag { get; set; }
public DateTime DateTime1 { get; set; }
public DateTime DateTime2 { get; set; }
public DateTime DateTime3 { get; set; }
public long Num1 { get; set; }
public uint Num2 { get; set; }
public uint Num3 { get; set; }
public ushort Num4 { get; set; }
}
public class MyObject2 : IMyObject
{
private int _num1;
public string Name { get; set; }
public object Tag { get; set; }
public DateTime DateTime1 { get; set; }
public DateTime DateTime2 { get; set; }
public DateTime DateTime3 { get; set; }
public long Num1
{
get { return _num1; }
set { _num1 = (int)value; }
}
public uint Num2 { get; set; }
public uint Num3 { get; set; }
public ushort Num4 { get; set; }
}
public class MyObject3 : IMyObject
{
public string Name { get; set; }
public object Tag { get; set; }
public DateTime DateTime1
{
get { return DateTime.MinValue; }
set { throw new NotSupportedException(); }
}
public DateTime DateTime2 { get; set; }
public DateTime DateTime3 { get; set; }
public long Num1 { get; set; }
public uint Num2 { get; set; }
public uint Num3 { get; set; }
public ushort Num4 { get; set; }
}
// ...
理论上,通过这种方法,我实际上可以减少内存占用量,但实际上如您所见,这种方法的问题在于它将导致所有情况下的笛卡尔积与较小和省略的字段,丑陋和大代码可以'在将来写完后要保持。
关于字符串的另一个想法:
.NET应用程序中的所有字符串都以UTF-16编码表示。如果我只能使它以UTF-8编码,它将减少字符串使用的内存的x2倍。
答案 0 :(得分:2)
思想:
Dictonary<string,string>
会这样做)int
)而不是引用;对于64位,这在加起来时是一个不错的保存DateTime
s - 他们(例如)总是整天?只需使用int
天数进入一个纪元,您就会感到惊讶答案 1 :(得分:1)
从查看你的个人资料,我将采取一个平底船,并猜测“名称”属性实际上是一个文件路径。如果空间比时间更重要,那么您可以使用编码方案来表示路径,其中可能存在大量重复数据。
将文件路径表示为Path,它是一个int数组,FileName是一个字符串和实际文件名(这可能更独特,因此不值得编码)。您可以将路径拆分为其组成部分,然后使用几个字典来存储正向和反向查找。通过这种方式,您可以减少int数组的路径。比字符串小得多。
答案 2 :(得分:1)
以UTF8存储字符串:
byte[] asciiStr = System.Text.Encoding.UTF8.GetBytes("asdf");
string text = System.Text.Encoding.UTF8.GetString(asciiStr);
(编辑:思想操作首先想要ASCII)
创意1 : 如果您希望大多数时间都不会填充大多数值,您可以将每个字段存储在某种单独的键值查找数据结构中 - 字典,带二进制搜索的有序列表,二叉树等..具有二进制搜索的有序列表可能是空间效率最高的,但查找将是O(log n)。
所以不是MyObject []对象,而是
Dictionary<int, string> names; // or List<Tuple<int,string>> names;
Dictionary<int, object> tags;
Dictionary<int, DateTime> datetime1s;
...
每个值中的int键是条目的ID。
创意2 : 如果你确信这些DateTimes在相当小的范围内(大约30年),比如2010年1月1日,你可以将它转换为32位int值,表示自该日期之前/之前的秒数。那将每个DateTime减少4个字节。
创意3 : 您可以考虑制作一个真正节省空间的序列化方案,其中每个字段的第一个字节指定后续字节中的哪个字段保存。字符串值可能只是用\ n或其他东西分隔。将整个事物存储在一个字节数组中,并按需反序列化。
这样的东西,没有空格,在适当的二进制值中:
1 //indicates field 1 (Name)
beck.asf\n //the value
6 //indicates field 6 (Num1)
3545623 //the value, in a 64-bit binary int
如果Tag引用了一个活动对象,您可能需要将它放在序列化之外的包装结构中。或者,与第一个想法一样,您可以只存储一个int,标识标记,然后使用List&gt;在外面,它包含对标签的实际引用。
答案 3 :(得分:0)