内存中的大型数据集 - .NET Framework和C#

时间:2011-03-28 07:36:24

标签: c# .net dll memory-management singleton

我有一个DLL项目,它使我的应用程序中使用的所有显示字符串的单例。问题是我需要在许多独立运行的应用程序中引用此DLL。

据我所知,如果我在所有独立运行的应用程序中引用DLL项目,它们都会将DLL加载到内存中并创建他们可以引用的单个单例,但这是我想要避免的冗余。

有没有办法可以将这个单例的一个实例保存在内存中并从所有独立项目中引用它?

我知道我可能听起来很愚蠢,而且这种装载可能根本没有发生,但我现在已经搜索了大约一个小时了。)

我使用.NET框架和C#作为目标语言。

4 个答案:

答案 0 :(得分:5)

通常,不同的进程具有不同的地址空间。由于DLL文件通常被加载到进程地址空间中,因此有必要编写一些特殊代码来实现进程之间的数据共享。通常,这是使用Windows API完成的,例如,在内存映射文件的帮助下。您可以在以下网址了解更多相关信息:

Sharing memory between two processes (C, Windows)

使用Windows API并不错,但它在某种程度上与.NET Framework理念相矛盾。我认为当单个服务器可以与不同的客户端一起工作并将所需的数据传递给它们时,最好创建一个客户端 - 服务器体系结构。例如,可以使用RemotingWCF来完成此操作。

答案 1 :(得分:2)

在真正出现问题之前,我不会为内存消耗而烦恼。我们可以做一些简单的数学运算:2 ^ 3(8)个应用程序中的2 ^ 13(8192)个字符串是2 ^ 16个字符串,如果一个字符串的平均大小为2 ^ 8(256)个字符,则所有字节的总字节数申请是2 * 2^24(32 MiB)。即使字符串的数量乘以10,这也不会造成任何问题。

其他解决方案所需的工作量将使其在当前阶段不可行。如果所有应用程序都使用大多数共享字符串,那么常见的字符串服务也没有任何好处。只有当一小部分字符串真正由它们共享时,它才能提供好处。

使用远程处理,您必须确保仅在一个位置初始化单例实例,并且必须通过接口访问它。您很可能想要创建一个本地单例实例,该实例从远程实例查询字符串。如果您继续使用旧的单例实现,直到需要其他解决方案,此解决方案也可以在之后实现。

如果你使用taskmanager跟踪内存使用情况,你应该在单例类中有一个非常大的字符串。

public static Strings {
    private readonly string MemoryUsageTest;

    static Strings() {
#if DEBUG
        int size = 104000000;
        var text = "abcdefghijklmnopqrstuvwxyz";
        var sb = new StringBuilder(size);

        for (int i = 0; i < size / text.Length; ++i) {
            sb.Append(text);
        }

        MemoryUsageTest = sb.ToString();
#endif
    }
}

我不太确定远程处理在任何时候都是一个不错的选择。无论如何,如果我们假设它是一个很好的替代方案,我建议当前的实现应该使用实现接口的单例类。这将使远程实例的使用变得更加容易。

public interface IStrings {
    string HelloWorld { get; }
}

public sealed class LocalStringService : IStrings {
    internal LocalStringService() { }

    string IStrings.HelloWorld {
        get { return "Hello World!"; }
    }
}

public static class StringService {
    private static readonly IStrings SingletonInstance = new LocalStringService();

    // If empty static constructor does not make any sense, read this:
    // http://csharpindepth.com/Articles/General/Beforefieldinit.aspx
    static StringService() { }

    public static IStrings Instance {
        get { return SingletonInstance; }
    }
}

现在,如果你想制作这个遥控器,你只需要将LocalStringService重命名为RemoteStringService,让它继承MarshalByRefObj并更改StringService以创建一个遥控器它的实例。此外,RemoteStringService应该在另一个程序集中,以便它不会与其他类一起加载到内存中。

尽管如此,我怀疑在这种情况下这会给你带来任何好处。

答案 2 :(得分:1)

使用的字符串常量很可能是实习。调用string.IsInterned静态函数来查看特定字符串。如果是这种情况,他们就不会占用过多的内存,因为每个字符串都在CLR实习池中。

IsInterned

答案 3 :(得分:1)

在此DLL文件上创建一个服务包装器,然后从其他应用程序调用该服务。