.NET Remoting Singleton memory leak, TCP, Маршалл по ссылке


Я использую самый простой пример удаленного взаимодействия, который я смог найти, совместное использование объекта между службой windows и программой windows forms (клиентом), работающей на одной машине.

Служба создает экземпляр объекта следующим образом:

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 в Диспетчере задач остается постоянным, даже если служба постоянно обновляет объект с информацией о состоянии. Когда клиент запущен, оба начинают увеличивать использование Mem и никогда не снижаются.

Это проблема, которую я упоминал в моем предыдущем вопросе о поиске утечек памяти.

Он появляется по-разному на разных машинах, некоторые показывают отсутствие увеличения памяти, но машины, которые это делают, будут надежно воспроизводить эту проблему. Запуск .NET Memory Profiler показывает, что в службе постоянно растет число "новых экземпляров", причем только один или два "удалены" на вкладке Types/Resources, где Namespace/System-ядро, а Name/Resource-HeapMemory. Я все еще пытаюсь научиться использовать профилировщик памяти, поэтому приношу извинения, если это неверная информация, и совет о том, где еще я должен искать, также будет оценен.

Этот объект является созданный один раз, всего с парой параметров для чтения и записи, без ввода-вывода файлов, без выделения памяти, которую я могу видеть, и все же мое использование памяти, кажется, только увеличивается в тот момент, когда я запускаю соединение от клиента к этому объекту и считываю его значения. Любой и все входные данные будут оценены, так как я хотел бы избежать вытягивания этого кода и замены его именованными каналами или подобными, но я быстро приближаюсь к этому пункту как к моему единственному варианту.

3 6

3 ответа:

Не должно там, где ваш сервис создает экземпляр объекта,

serviceConfigRemote = new serviceConfigDataRemote();

Похоже на

serviceConfigRemote = serviceConfigDataRemote.Instance;

Вместо этого?

По крайней мере, так, как у вас есть, вы создаете два разных экземпляра на стороне сервера, один в статическом инициализаторе instance члена, который будет использоваться свойством Instance, а другой через явную конструкцию new serviceConfigDataRemote(). Также может быть полезно добавить частный конструктор к этому классу, чтобы ничто другое не могло создать экземпляр синглтона, кроме статического инициализатор.

Возможно, это и не является решением проблемы постоянно увеличивающейся памяти, но это определенно кажется чем-то вроде проблемы, требующей решения.

Правка:

Вот еще пара советов, которые я нашел, прочесывая сети:

  • добавьте [MTAThread] к основному методу службы хоста.
  • RemotingServices.Disconnect(this.serviceConfigRemote); Когда вы отключаете службу хоста.

Надеюсь, что это может помочь.

Вы пытались использовать "ленивое" создание экземпляра на ваш Синглтон. Возможно, ему не нравится, как вы его создаете.

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; }
        }
    }

Поскольку единственная ОС, в которой вы видите эту ошибку, - это XP, есть несколько возможных проблем.

  1. XP имеет ограничение на входящее соединение 10 (на pro) или 5 (на home) , и это может сыграть определенную роль в проблеме.

  2. Убедитесь, что установлены все пакеты обновления/исправления. Я знаю, что это может быть банальным и шаблонным ответом на любые проблемы, но тот факт, что эта проблема появляется только в XP, подразумевает, что она связана с ОС.

Кроме того, не уверен, как вы используете сервис, но Windows XP-это настольная ОС,а не серверная. Если вы хотите, чтобы сервис был сервером какого-то типа, вы действительно должны использовать 2000/2003/2008 и т. д., Тем более, что он имеет проблемы только на XP.