Я столкнулся с кажущейся утечкой ручек, используя компонент Borland/Embarcadero TClientSocket
. У меня есть приложение, которое создает несколько экземпляров TThread
, каждый из которых динамически создает объект TClientSocket
, подключается к его цели, отправляет несколько сообщений, а затем удаляется. Затем экземпляры TThread
удаляются (используя параметр FreeOnTerminate = true
). Я знаю, что это неэффективно, но оно идеально подходит для приложений приложения - максимальное количество экземпляров TThread
, способных к одновременному использованию, ограничено 32. Проблема, которую я вижу, заключается в том, что существует явная проблема с утечкой окон, с которой я могу см. с помощью диспетчера задач. В попытке изолировать проблему я применил ту же проблему в одном потоковом смысле, просто динамически создавая объект TClientSocket
и удаляя его снова, когда закончил с помощью одного цикла в основном потоке VCL. Это проявляет ту же самую проблему с утечкой рукоятки. Я знаю, что компонент устарел, и я знаю, что то, что я делаю, неэффективно, но я не понимаю, почему будет утечка дескриптора. Есть ли что-то, что нужно сделать с объектами TClientSocket
до их удаления, чтобы удалить эту утечку дескриптора, или это ошибка в компоненте? Я использую сокет в неблокирующем режиме и назначая обработчики событий OnConnect
OnDisconnect
и OnSocketError
.Приложение C++, вызывающее утечку Windows с использованием нескольких экземпляров TClientSocket
ответ
Я использовал TClientSocket
в течение многих лет, включая использование в основной теме и в рабочей нити, и я никогда не видел TClientSocket
утечки любых ручек.
Однако TClientSocket
делает по умолчанию в неблокирующем режиме, и в этом режиме он использует AllocateHWnd()
создать скрытое окно, чтобы получить сокет события и AllocateHWnd()
является не поточно-. Не видя своего фактического кода, это вероятная причина утечек, которые вы видите в коде рабочего потока. Решение этого вопроса просто не использовать TClientSocket
является неблокирующим режимом при использовании в рабочем потоке. Вместо этого используйте его в режиме блокировки. В любом случае, лучше всего подходит логика на основе потоков.
Однако это не объясняет утечки, которые вы видите в коде основного потока. Я сомневаюсь, что TClientSocket
на самом деле является виновником, и снова, не видя своего фактического кода, трудно сказать наверняка.
Спасибо за этот ответ. Я просто взглянул на документацию Embarcadero для 'AllocateHWnd()' - на основе того, что вы говорите, что также подразумевает, что небезопасно использовать объекты «TTimer» в потоках также? – mathematician1975
@ mathematician1975: yes, 'TTimer' использует' AllocateHWnd() ', поэтому' TTimer' небезопасно использовать в рабочих потоках. Но есть лучшие альтернативы для поточных таймеров, таких как 'CreateWaitableTimer()'. –
Спасибо за информацию. Я думаю, что я просто переписал все, чтобы использовать блокирующий клиент. – mathematician1975
SO_LINGER возможно? Просто гадать здесь. Я был бы удивлен, если бы это было так, как это было бы неожиданно, но стоило бы короткого, если бы вы могли получить этот гранулированный контроль над базовым сокетом. – WhozCraig
@WhozCraig: 'SO_LINGER' не имеет ничего общего с ручками. Но да, возможно получить доступ к основному дескриптору 'SOCKET', используемому' TClientSocket' (через свойство 'TClientSocket.Socket.SocketHandle') и напрямую вызвать на нем функции WinSock API, такие как' setsockopt() '. –
@RemyLebeu Нет ли ручки ввода-вывода за этим сокетом? I.e, если я открою 10 000 сокетов и запустил procexp, я * не * увижу пропорциональный счетчик ручек? Я только поднял его, потому что у меня была аналогичная проблема с приложением большого объема быстрого отсоединения, и это была именно проблема. после отключения, не убивая таймер задержки, ручки не были немедленно возвращены. Как я уже сказал, я полагаюсь на более узнаваемый, который похож на вас. Спасибо за информацию. – WhozCraig