Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
[perl] Каким образом освободить память?
|
|||
|---|---|---|---|
|
#18+
Доброго дня. Хочу немного допилить долгоиграющий скрипт. Проблема в том, что при длительной работе отжирание памяти растет и растет. Причина, как мне кажется, в том, что ставшие ненужными ресурсы не освобождаются. Сам скрипт представляет собой FTP-прокси. Будучи запущенным, он принимает подключения клиентов по 21 порту (канал управления), заменяет данные для подключения (подставляет реальный пароль), логгирует действия клиентов и т.п. Скрипт был писан давно и не мною. Работает - и ладно, но при активной работе клиентов процесс пухнет до несколько сотен мегабайт. Чтобы показать структуру, под спойлером приведу частично фрагменты кода. Код: php 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. Если правильно понимаю, нужно каким-то образом очистить память после выхода из экземпляра из уже ненужного инстанса sub client, который стартовал в строке: Код: php 1. 2. Но где и как это сделать правильно? Еще один момент для некоторой оптимизации, как мне кажется, это освобождение неиспользуемых переменных. Подскажите, какими принципами следует руководствоваться для такой вот структуры? Сам я не сталкивался никогда с тредами. Да и оптимизацией перловых скриптов не занимался. Потому прошу наставить на путь истинный. Заранее благодарю. PS: По крону перестартовать скрипт - это, конечно, тоже решение. Но не слишком удачное, на мой взгляд. :-) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2014, 15:53 |
|
||
|
[perl] Каким образом освободить память?
|
|||
|---|---|---|---|
|
#18+
vkle, Что может быть надёжней, старого, доброго "RESET:)", если что-то непомерно начинает жрать память и CP, и процесс начинает тормозить работу всей системы, самое надёжное прервать (перезапустить процесс). Возможно скрипт так и написан, что со временем начинает перегружать память.. Может косяк.. а может по другому никак.. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2014, 17:16 |
|
||
|
[perl] Каким образом освободить память?
|
|||
|---|---|---|---|
|
#18+
Goror, Ну так вот уж несколько лет и делаем - как заглючило - так убиваем процесс. Сейчас сервис на другую машину перенес. Костыли поубирать хочу. Или проще написать еще один сервис, который мониторит этот скрип на предмет обжорства и принимает убойные меры? Должен же быть какой-то unset или что-то вроде... Не? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2014, 17:43 |
|
||
|
[perl] Каким образом освободить память?
|
|||
|---|---|---|---|
|
#18+
vkleЕсли правильно понимаю, нужно каким-то образом очистить память после выхода из экземпляра из уже ненужного инстанса sub client, который стартовал в строке: Код: php 1. 2. Но где и как это сделать правильно? Ну в общем, да. Поубивать все что создано внутри нити и в конце вызвать threads->exit(). Это надо делать конечно же внутри того самого "ненужного инстанса", а не в главном потоке. Этого должно хватать. vkleЕще один момент для некоторой оптимизации, как мне кажется, это освобождение неиспользуемых переменных. Подскажите, какими принципами следует руководствоваться для такой вот структуры?Ну так и делать. Все что появляется на куче изнутри нити, должно нитью же и освобождаться. Еще можно повторно использовать освободившиеся нити. Если клиент ушел - нить помечается как простаивающая и следующий клиент отдается в уже существующую. Но это надо будет переделывать твой проект. vklePS: По крону перестартовать скрипт - это, конечно, тоже решение. Но не слишком удачное, на мой взгляд. :-)Ну если уж совсем приперло, то... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2014, 19:45 |
|
||
|
[perl] Каким образом освободить память?
|
|||
|---|---|---|---|
|
#18+
White OwlvkleЕсли правильно понимаю, нужно каким-то образом очистить память после выхода из экземпляра из уже ненужного инстанса sub client, который стартовал в строке: Код: php 1. 2. Но где и как это сделать правильно? Ну в общем, да. Поубивать все что создано внутри нити и в конце вызвать threads->exit(). Это надо делать конечно же внутри того самого "ненужного инстанса", а не в главном потоке. Этого должно хватать. Спасибо за ответ. Пытаюсь сперва понять суть и осознать принципы. Потому появились вопросы для уточнения понимания. В текущем варианте выход из sub client сделан через return 0 . В таком случае после выхода по return 0 в пеерменной $threads[$count] остается ставший ненужным экземпляр "клиента". Но ведь и после threads->exit() в $threads останется индекс уже несуществующего элемента. Его нужно убирать в главном потоке или он сам исчезнет? Вроде сам то не должен исчезнуть... Еще хочу уточнить, куда помещать threads->exit() - по логике получается что как раз вместо return 0 . Если строкой ранее - то return окажется бесполезен (ошибаюсь?), а если следующей строкой - то завершение работы нити по exit попросту никогда не выполнится. Верно мыслю? Про созданные внутри нити переменные, если можно, несколько слов. Их нужно индивидуально каждую прихлопнуть, или достаточно внутри sub client объявить их как my и они по threads->exit() прекратят свое существование, освободив память? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.07.2014, 21:38 |
|
||
|
[perl] Каким образом освободить память?
|
|||
|---|---|---|---|
|
#18+
vkleВ текущем варианте выход из sub client сделан через return 0 . В таком случае после выхода по return 0 в пеерменной $threads[$count] остается ставший ненужным экземпляр "клиента". Но ведь и после threads->exit() в $threads останется индекс уже несуществующего элемента. Его нужно убирать в главном потоке или он сам исчезнет? Вроде сам то не должен исчезнуть...Просто return 0 это нормально. threads->exit() используется для "неожиданного" завершения нити. И поток это не процесс, он как раз должен исчезать сам. Если ты думаешь о zombie-процессах, то нет, в перловом варианте нитей этого нет. vkleЕще хочу уточнить, куда помещать threads->exit() - по логике получается что как раз вместо return 0 . Если строкой ранее - то return окажется бесполезен (ошибаюсь?), а если следующей строкой - то завершение работы нити по exit попросту никогда не выполнится. Верно мыслю?Все верно. vkleПро созданные внутри нити переменные, если можно, несколько слов. Их нужно индивидуально каждую прихлопнуть, или достаточно внутри sub client объявить их как my и они по threads->exit() прекратят свое существование, освободив память?Если это примитивные переменные, то my достаточно. А если это нечто созданное через somemodule->new, то недостаточно. Си знаешь? Разницу между стековыми переменными и памятью на куче знаешь? Вот это оно и есть. my - стек, new() - куча. Навскидку, в том огрызке что ты привел, я вижу `$dbh = DBI->connect() / $dbh->disconnect()` этого мало. На DBI->connect() делается не только коннект к базе, но и инициализация библиотек которые собственно делают коннект. А dbh->disconnect() не обязан эти библиотеки выгружать. А вдруг ты два коннекта открыл к двум разным базам? Плюс к этому, сами интерфейсные библиотеки могут делать кучу всякого разного, до чего никак не добраться снаружи. И при всем этом, у DBI нету метода "выгрузить все". В общем, я в первую очередь убрал бы отсюда всю работу с СУБД. Если я правильно понимаю задачу, то тебе вполне хватит отдавать в клиентскую нить хеш-массив который ты будешь создавать один раз при старте программы. Ну и если нужно, раз в час/сутки/год пусть главный поток отвлекается от ожидания клиентов и перечитывает список переадресации - перестраивает этот хеш-массив. Если СУБД обязательно нужна внутри нити, то лучше будет вместо DBI использовать что-нибудь другое, более thread-friendly. В идеале вообще, лучше взять оригинальные интерфейсные библиотеки, и сделать свой модуль с оглядкой на их thread-safety как рекомендуют авторы СУБД. Ну или найти соответствующий модуль. Но DBI точно надо убрать нафиг. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.07.2014, 01:48 |
|
||
|
[perl] Каким образом освободить память?
|
|||
|---|---|---|---|
|
#18+
White OwlvkleВ текущем варианте выход из sub client сделан через return 0 . В таком случае после выхода по return 0 в пеерменной $threads[$count] остается ставший ненужным экземпляр "клиента". Но ведь и после threads->exit() в $threads останется индекс уже несуществующего элемента. Его нужно убирать в главном потоке или он сам исчезнет? Вроде сам то не должен исчезнуть...Просто return 0 это нормально. threads->exit() используется для "неожиданного" завершения нити. И поток это не процесс, он как раз должен исчезать сам. Если ты думаешь о zombie-процессах, то нет, в перловом варианте нитей этого нет.Благодарю за развернутый ответ. Здесь я думаю не о зомби. Я думаю, что после завершения нити ссылка на нее (на эту нить) будет храниться в $threads[$count]. В каком месте делать для нее undef - вот что не понятно. White OwlЕсли СУБД обязательно нужна внутри нити, то лучше будет вместо DBI использовать что-нибудь другое, более thread-friendly. В идеале вообще, лучше взять оригинальные интерфейсные библиотеки, и сделать свой модуль с оглядкой на их thread-safety как рекомендуют авторы СУБД. Ну или найти соответствующий модуль. Но DBI точно надо убрать нафиг.Тоже подумал что DBI как-то корявенько внутри нити. В текущей реализации на каждого клиента открывается новый коннект к БД. Выносить его в основную программу - как то не слишком надежно. Полагаю, что автор сделал коннект именно внутри нити на случай временной недоступности СУБД (в таком случае клиенту достаточно заново подключться когда СУБД будет доступна). Можете порекомендовать какое-то thread-friendly решение или модуль? Сейчас попробовал сделать изменения в скрипте: - все переменные внутри sub client определил через my, - return 0 заменил везде на threads->exit(), - и к $dbh->disconnect везде добавил еще undef $dbh. По результатам беглого тестирования никакого существенного изменения по отъеданию памяти не обнаружил - только растет. Видимо, этих мер недостаточно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.07.2014, 18:53 |
|
||
|
[perl] Каким образом освободить память?
|
|||
|---|---|---|---|
|
#18+
vkleЯ думаю, что после завершения нити ссылка на нее (на эту нить) будет храниться в $threads[$count]. В каком месте делать для нее undef - вот что не понятно.Не надо делать, само сделается. Когда нить завершается она автоматом уходит из списка. Конечно если у тебя есть собственная переменная, в которой хранится ссылка на свежезапущенный поток, то надо будет вручную отслеживать когда ее чистить ($thr->is_running() спасет :)) Но список нитей которые ведет сам модуль threads обновляется (и чистится) автоматом. vkleМожете порекомендовать какое-то thread-friendly решение или модуль?Это не ко мне. Я с MySQL практически не работаю. Но на cpan лежит куча MySQL модулей кроме DBD::MySQL. Ну и можешь спросить на соответствующем форуме, как можно сделать потоко-безопасное подключение из Си и потом искать соответствующий модуль. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.07.2014, 19:48 |
|
||
|
[perl] Каким образом освободить память?
|
|||
|---|---|---|---|
|
#18+
White OwlКонечно если у тебя есть собственная переменная, в которой хранится ссылка на свежезапущенный поток, то надо будет вручную отслеживать когда ее чистить ($thr->is_running() спасет :))Хм, действительно, чего-то я тупанул... Переменная то для хранения нити есть, но она вроде как более нигде не используется. Завтра попробую убрать ее. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.07.2014, 22:17 |
|
||
|
|

start [/forum/topic.php?fid=23&fpage=82&tid=1462617]: |
0ms |
get settings: |
10ms |
get forum list: |
17ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
68ms |
get topic data: |
14ms |
get forum data: |
3ms |
get page messages: |
61ms |
get tp. blocked users: |
2ms |
| others: | 252ms |
| total: | 435ms |

| 0 / 0 |
