.NET Remoting Singleton内存泄漏,TCP,Marshal by Reference

时间:2009-12-04 19:43:20

标签: c# .net memory-leaks remoting marshalling

我正在使用我能找到的最简单的远程处理示例,在Windows服务和Windows窗体程序(客户端)之间共享一个对象,在同一台机器上运行。

服务实例化对象如下:

serviceConfigRemote = new serviceConfigDataRemote();
serverChannel = new TcpServerChannel(9090);
ChannelServices.RegisterChannel(serverChannel, false);
RemotingServices.Marshal(this.serviceConfigRemote, "ServiceConfigData");

客户端建立如下连接:

TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel, false);
configData = (serviceConfigDataRemote)Activator.GetObject(typeof(serviceConfigDataRemote), "tcp://localhost:9090/ServiceConfigData");

这个想法是服务能够更改对象的某些参数,以便客户端能够读取这些更改。

对象本身是:

public sealed class serviceConfigDataRemote : MarshalByRefObject
{
    private bool myConnectedFlag;
    private bool mySendingFlag;
    private bool myUpdateFlag;
    private string myClientConfiguration;

    static readonly serviceConfigDataRemote instance = new serviceConfigDataRemote();

    static serviceConfigDataRemote()
    {
    }

    public serviceConfigDataRemote()
    {
        myConnectedFlag = false;
        mySendingFlag = false;
        myUpdateFlag = false;
        myClientConfiguration = "";
    }

    public static serviceConfigDataRemote Instance
    {
        get
        {
            return instance;
        }
    }

    public override object InitializeLifetimeService()
    {
        return (null);
    }


    public bool Connected
    {
        get { return myConnectedFlag; }
        set { myConnectedFlag = value; }
    }

    public bool Sending
    {
        get { return mySendingFlag; }
        set { mySendingFlag = value; }
    }

    public bool CheckForUpdates
    {
        get{return myUpdateFlag;}
        set { myUpdateFlag = value; }
    }

    public string ClientConfiguration
    {
        get { return myClientConfiguration; }
        set { myClientConfiguration = value; }
    }
}

当服务自行运行时,任务管理器中的Mem Usage保持不变,即使服务不断使用状态信息更新对象。当客户端启动时,两者都开始在Mem Usage中增加,并且永远不会下降。

这是我在My Previous Question中提到的关于发现内存泄漏的问题。

在不同的机器上出现的情况有所不同,有些显示没有内存增加,但是这些机器可以可靠地重现这个问题。运行.NET Memory Profiler显示,在服务上,“新实例”的数量不断增加,在选项卡类型/资源中只有一个或两个“已删除”,其中命名空间/系统是内核,名称/资源是HeapMemory。我还在努力学习如何使用Memory Profiler,所以如果这是错误的信息我会道歉,并且我还应该感谢其他我想看的地方。

这个对象被实例化一次,只有几个参数可以读写,没有文件io,没有我可以看到的内存分配,但是我的内存使用量似乎只是从我开始连接的那一刻开始客户端到该对象并读取其值。任何和所有输入都将被赞赏,因为我想避免拉动此代码并用命名管道或类似替换它,但我很快就接近这一点作为我唯一的选择。

3 个答案:

答案 0 :(得分:3)

不应该在服务实例化对象的地方

serviceConfigRemote = new serviceConfigDataRemote();

看起来像

serviceConfigRemote = serviceConfigDataRemote.Instance;

代替?

至少,你拥有它的方式,你在服务器端创建两个不同的实例,一个在静态instance成员初始化器中,由Instance属性使用,另一个一个通过new serviceConfigDataRemote()显式构造。它也可以很好地为该类添加一个私有构造函数,因此除了静态初始化程序之外,没有其他任何东西可以实例化单例。

这可能不是日益增长的记忆的解决方案,但它似乎是一个需要解决的问题。

编辑:

以下是我在网上搜索的一些提示:

  • [MTAThread]添加到主机服务的主方法。
  • 当你关闭主机服务时,
  • RemotingServices.Disconnect(this.serviceConfigRemote);

希望这可能会有所帮助。

答案 1 :(得分:1)

您是否尝试在Singleton上使用延迟实例化。它可能不喜欢你实例化它的方式。

public sealed class serviceConfigDataRemote : MarshalByRefObject
    {
        private bool myConnectedFlag;
        private bool mySendingFlag;
        private bool myUpdateFlag;
        private string myClientConfiguration;

        static serviceConfigDataRemote instance;

        static serviceConfigDataRemote()
        {
        }

        public serviceConfigDataRemote()
        {
            myConnectedFlag = false;
            mySendingFlag = false;
            myUpdateFlag = false;
            myClientConfiguration = "";
        }

        public static serviceConfigDataRemote Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (new Object())
                    {
                        if (instance == null)
                        {
                            instance = new serviceConfigDataRemote();
                        }
                        return instance;
                    }
                }
                return instance;
            }
        }

        public override object InitializeLifetimeService()
        {
            return (null);
        }


        public bool Connected
        {
            get { return myConnectedFlag; }
            set { myConnectedFlag = value; }
        }

        public bool Sending
        {
            get { return mySendingFlag; }
            set { mySendingFlag = value; }
        }

        public bool CheckForUpdates
        {
            get { return myUpdateFlag; }
            set { myUpdateFlag = value; }
        }

        public string ClientConfiguration
        {
            get { return myClientConfiguration; }
            set { myClientConfiguration = value; }
        }
    }

答案 2 :(得分:0)

由于您遇到此漏洞的唯一操作系统是XP,因此存在一些可能的问题。

  1. XP的传入连接限制为10(专业版)或5(家庭版),这可能会解决问题。

  2. 确保已安装所有Service Pack /修补程序。我知道这可能是任何问题的陈词滥调和陈词滥调,但事实上这个问题只出现在XP中意味着它与操作系统有关。

  3. 此外,不确定您是如何使用该服务的,但Windows XP是桌面操作系统,而不是服务器操作系统。如果您打算将服务作为某种类型的服务器,那么您真的应该使用2000/2003/2008等,特别是因为它只有XP上的问题。