我可以使用C#中内存使用有限的结构(字典)?

我可以使用C#中内存使用有限的结构(字典)?,c#,memory-management,dictionary,C#,Memory Management,Dictionary,告诉我什么库(最好是纯.NET)可以用于以下问题。有字典 Dictionary < long, MyData > 字典包含数百万个条目,这是由于消耗了1-2G的内存,这取决于填充MyData 我想找到一个类似于Dictionary的数据结构,但我可以指定内存消耗的最大大小,如果内存用完,那么长时间未访问的数据就会进入硬盘。 如果对象是通过键请求的,并且对象存储在硬盘上,则应将其加载到内存中 一般来说,我在.NET库中搜索具有此类要求的键/值存储。 1.我必须能够指定存储的最大RAM使用量

告诉我什么库(最好是纯.NET)可以用于以下问题。有字典 Dictionary < long, MyData > 字典包含数百万个条目,这是由于消耗了1-2G的内存,这取决于填充MyData

我想找到一个类似于Dictionary的数据结构,但我可以指定内存消耗的最大大小,如果内存用完,那么长时间未访问的数据就会进入硬盘。 如果对象是通过键请求的,并且对象存储在硬盘上,则应将其加载到内存中

一般来说,我在.NET库中搜索具有此类要求的键/值存储。 1.我必须能够指定存储的最大RAM使用量 2.它应该使用磁盘进行交换。
2.它应该很快。

我认为没有一个本机的.net解决方案可以解决您的问题,即能够在内存中存储千兆字节的对象,并使它们可以搜索、备份到磁盘和提高内存效率

但也有一些工具可以做到这一点。您正在寻找的一般概念可能是文档数据库(或NoSQL)


如果你主要关注的是让事情变得可搜索,我以前有Lucene.Net。还有很多键/值对工具(我没有使用过,但也许其他人可以提出他们的建议)。

我不相信有一个本机的.net解决方案可以解决您在内存中存储千兆字节的对象并使它们可搜索、可备份到磁盘和内存效率高的问题

但也有一些工具可以做到这一点。您正在寻找的一般概念可能是文档数据库(或NoSQL)


如果你主要关注的是让事情变得可搜索,我以前有Lucene.Net。还有很多键/值对工具(我没有使用过,但也许其他人可以提出他们的建议)。

我不相信有一个本机的.net解决方案可以解决您在内存中存储千兆字节的对象并使它们可搜索、可备份到磁盘和内存效率高的问题

但也有一些工具可以做到这一点。您正在寻找的一般概念可能是文档数据库(或NoSQL)


如果你主要关注的是让事情变得可搜索,我以前有Lucene.Net。还有很多键/值对工具(我没有使用过,但也许其他人可以提出他们的建议)。

我不相信有一个本机的.net解决方案可以解决您在内存中存储千兆字节的对象并使它们可搜索、可备份到磁盘和内存效率高的问题

但也有一些工具可以做到这一点。您正在寻找的一般概念可能是文档数据库(或NoSQL)


如果你主要关注的是让事情变得可搜索,我以前有Lucene.Net。还有很多键/值对工具(我没有使用过任何工具,但也许其他人可以提出他们的建议)。

如果您使用的是64位,您可能需要

2a。它应该使用磁盘进行交换

2b。应该很快

免费忽略先决条件。Windows交换未使用的内存块,然后在加载这些内存块时进行交换。因此,您可以简单地忽略内存使用,让Windows通过交换文件来处理它。唯一的问题可能是,如果您的
MyData
是一个“引用树”,其中一个“主”对象连接(引用)到其他对象。这些子对象中的每一个子对象都可以位于内存的不同部分,因此可以分别进行换入/换出


请注意,作为一种简单的替代方法,您可以尝试使用
protobuf
MyData
进行序列化,然后使用
DeflateStream
在内存中对其进行压缩,保留一个
byte[]
而不是原始的
MyData
。。。显然,当需要数据时,您必须执行相反的操作。

如果您使用的是64位,您可能需要

2a。它应该使用磁盘进行交换

2b。应该很快

免费忽略先决条件。Windows交换未使用的内存块,然后在加载这些内存块时进行交换。因此,您可以简单地忽略内存使用,让Windows通过交换文件来处理它。唯一的问题可能是,如果您的
MyData
是一个“引用树”,其中一个“主”对象连接(引用)到其他对象。这些子对象中的每一个子对象都可以位于内存的不同部分,因此可以分别进行换入/换出


请注意,作为一种简单的替代方法,您可以尝试使用
protobuf
MyData
进行序列化,然后使用
DeflateStream
在内存中对其进行压缩,保留一个
byte[]
而不是原始的
MyData
。。。显然,当需要数据时,您必须执行相反的操作。

如果您使用的是64位,您可能需要

2a。它应该使用磁盘进行交换

2b。应该很快

免费忽略先决条件。Windows交换未使用的内存块,然后在加载这些内存块时进行交换。因此,您可以简单地忽略内存使用,让Windows通过交换文件来处理它。唯一的问题可能是,如果您的
MyData
是一个“引用树”,其中一个“主”对象连接(引用)到其他对象。这些子对象中的每一个子对象都可以位于内存的不同部分,因此可以分别进行换入/换出


请注意,作为一种简单的替代方法,您可以尝试使用
protobuf
MyData
进行序列化,然后使用
DeflateStream
在内存中对其进行压缩,保留一个
byte[]
而不是原始的
MyData
。。。显然,当需要数据时,您必须执行相反的操作。

如果您使用的是64位,您可以
public interface IPersistanceProvider<TValue>
{
    void Save(string key, TValue value);
    TValue Load(string key);
}
public sealed class CustomCache<TValue> : IDisposable
    where TValue: class
{
    private readonly TimeSpan _slidingExpirationWindow;
    private readonly IPersistanceProvider<TValue> _persistanceProvider;
    private readonly MemoryCache _cache;

    /// <summary>
    /// A custom cache that writes items out to a IPersistanceProvider when the item is evicted from the cache.
    /// </summary>
    /// <param name="slidingExpirationWindow">The amount of time before the item is automatically evicted if it has not been accessed.</param>
    /// <param name="cacheMemoryLimitMegabytes">The maximum size the cache can be before it starts force evicting items.</param>
    /// <param name="persistanceProvider">The service that will save and load data to a persistent storage.</param>
    public CustomCache(TimeSpan slidingExpirationWindow, int cacheMemoryLimitMegabytes, IPersistanceProvider<TValue> persistanceProvider)
    {
        _slidingExpirationWindow = slidingExpirationWindow;
        _persistanceProvider = persistanceProvider;

        _cache = new MemoryCache("", new NameValueCollection { { "CacheMemoryLimitMegabytes", cacheMemoryLimitMegabytes.ToString("D") } });
    }

    public void SetItem(string key, TValue value)
    {
        if (key == null)
            throw new ArgumentNullException("key");

        if (value == null)
            throw new ArgumentNullException("value");

        SetCacheItem(key, value);
    }

    public TValue GetItem(string key)
    {
        if (key == null)
            throw new ArgumentNullException("key");

        var item = _cache.Get(key);
        if (item == null)
        {
            item = _persistanceProvider.Load(key);
            SetCacheItem(key, item);
        }

        return (TValue)item;
    }

    public void RemoveItem(string key)
    {
        if (key == null)
            throw new ArgumentNullException("key");

        _cache.Remove(key);
    }

    public void Dispose()
    {
        if (_cache != null)
        {
            _cache.Dispose();
        }
    }

    private void SetCacheItem(string key, object value)
    {
        var policy = new CacheItemPolicy();
        policy.RemovedCallback = RemovedCallback;
        policy.SlidingExpiration = _slidingExpirationWindow;

        _cache.Set(key, value, policy);
    }

    private void RemovedCallback(CacheEntryRemovedArguments arguments)
    {
        if (arguments.RemovedReason == CacheEntryRemovedReason.Removed)
            return;

        _persistanceProvider.Save(arguments.CacheItem.Key, (TValue)arguments.CacheItem.Value);
    }
}