Всегда были проблемы при работе с памятью, и сейчас возник следующий вопрос. У меня в программе на Си в Linux'е используется динамический список. Соответственно есть два потока: один добавляет в список записи, другой их обрабатывает и удаляет. Для выделения/очистки памяти используется *alloc/free. Добавление происходит быстрей удаления, что естественно ведет к постоянному росту списка, что в конечном счете может привести к переполнению памяти. Соответственно вопрос, как этого избежать? Можно ли, например, задать программе (внутри самой программы) какое-то ограничение на объем доступной памяти, и при этом, соответственно, определить момент, когда этот предел будет достигнут (в этом случае можно было бы делать паузу и ждать, пока снова не появится достаточно доступной памяти)? Просто подсчитывать количество выделенной памяти ведь не подойдет, так как выделяемые и освобождаемые участки памяти всегда разной длины, что ведет к дефрагментации и в конечном счете доступно будет гораздо меньше памяти, чем действительно свободно.Кроме того, я пытался использовать процессы вместо потоков и разделяемую память, но в этом случае ограничение на объем доступной разделяемой памяти оказался слишком маленький (не то 32Мб, не то 64). Может кто-нибудь знает, как увеличить это ограничение хотя бы до 2Гб?
И забыл сказать. Программа написана под Red Hat Enterprise Linux 3.0 (ядро linux 2.4.21)
>Добавление происходит быстрей удаления, что естественно ведет к постоянному росту
> к переполнению памяти. Соответственно вопрос, как этого избежать?Неужели удалять быстрее, чем добавляешь??
Может быть, подумать, кой чорт понёс^W^W^Wзачем тебе понадобились потоки/форки? Сделать _выводы_.
Например, читать-писать _последовательно_ в __одном__ потоке. Или исхитриться и читать двумя или более потоками, коли уж один "не успевает" (это не избавляет от необходимости синхронизации/блокировки ресурсов или какого ни IPC; и разнесения читателей по разным cpu). Оптимизировать производительность читателя, чтоб успевал. Купить сервер, чтоб успевал. Купить много серверов, чтоб успевали. Ещё ускорять читателя - отложить часть работы, например, "синхронно" писать на диск, потом медленно/асинхронно оборабатывать. Диск он большой -- авось поместится.
100рублейвкассублин!
2Maxim Chirkov: Гы, куда страждущим переводить _деньги_ за консультацию? Заведи кошелёк opennet что ли?.. %-)) И доп.поле "[_ ] руб. в кассу!", и ключь-идентификатор для вписывания в квиток %) перевода, и "лампочку" [ОПЛАЧЕНО] на ответах. :D Желаю анонимно зарабатывать денег уважаемому сайту и немеряной, но оцененной Славы. Как бы ещё анонимных неплательщиком пиночить? %)
>конечном счете доступно будет гораздо меньше памяти, чем действительно свободно.
Феерично.......
>Может кто-нибудь знает, как увеличить это ограничение хотя бы до 2Гб?
Вам, может быть, нужен програмист?
>И забыл сказать. Программа написана под Red Hat Enterprise Linux 3.0 (ядро linux 2.4.21)
Не-е-е, в интырпрайз программировании тут никто ничего не понимает... Это Вам на бизнес-кусы надо.
Видимо моя ошибка, что не описал задачу подробней. Хотя и причин для смеха в своем текте я не нахожу.>Неужели удалять быстрее, чем добавляешь??
>
>Может быть, подумать, кой чорт понёс^W^W^Wзачем тебе понадобились потоки/форки? Сделать _выводы_.
>Удаляю я как раз медленней, о чем и написал. Потому что первый поток только добавляет, а второй еще и обработкой занимается с записью обработанных данных в БД. Из-за работы с БД основные тормаза и идут. Поэтому и используется конвеер, чтобы успевать принимать данные. И в данный момент используются процессы (форки) с промежуточным буфером в разделяемой памяти. И тут-то встала проблема, что в разделяемой памяти буфер может быть не больше 32/64Мб. Как увеличить этот предел - мне не известно. Хочу перевести это дело на потоки, так как с потоками все данные находятся в одном адресном пространстве, но встает проблема с тем, как контралировать заполнение памяти так, чтобы не прейти к переполнению.
>Например, читать-писать _последовательно_ в __одном__ потоке. Или исхитриться и читать двумя или
>более потоками, коли уж один "не успевает" (это не избавляет от
>необходимости синхронизации/блокировки ресурсов или какого ни IPC; и разнесения читателей по
>разным cpu). Оптимизировать производительность читателя, чтоб успевал. Купить сервер, чтоб успевал.
>Купить много серверов, чтоб успевали. Ещё ускорять читателя - отложить часть
>работы, например, "синхронно" писать на диск, потом медленно/асинхронно оборабатывать. Диск он
>большой -- авось поместится.
>Двумя и более потоками читать не получится. Слишком муторно и труднореализуемо, если вообще реализуемо. Мощность сервера и без того достаточная. Вся загвоздка в том, что данные приходят быстрей, чем программа, успевает их записать в БД. Тут все утыкается в производительность дискового массива, который используется для хранения БД, но его заменить щас не возможно. Да и замена его на более быстрый думаю не сильно бы помогла. Поэтому все опять же возвращается к означенным мной ранее вопросом, на которые я надеюсь кто-нибудь таки сможет мне ответить.
1. менять дизайн проги по любому -- т.к. передача данных от процесса к процессу не есть верный способ.
2. у современных БД есть асинхронные вызовы
3. если БД не успевает это записывать из-за диска это одно, если из-за того что не оптимизированы запросы/таблицы это другое
4. если БД оптимизировать нельзя, и запись не успевает нужно менять железо как не подходящее для задачи.
всё это напоминает решение задачи "считаем трафик", только через Жчто хоть прога делает? -- частенько встречаются случаи с неверной постановкой задачи и соответствующей реализацией
>Всегда были проблемы при работе с памятью, и сейчас возник следующий вопрос.Изучайте матчасть и закрывайте пробелы.
>У меня в программе на Си в Linux'е используется динамический список.
переходите на с++ что ли, уже 2009 год на дворе и эта ваша фраза как-то пугает, видимо наследуемый код, если нет, то страшно..
>Соответственно есть два потока: один добавляет в список записи, другой их
>обрабатывает и удаляет. Для выделения/очистки памяти используется *alloc/free.есть тулза от гугла (google perf tools или как-то так) которая подменяет стандартный malloc на свою реализацию заточеную под очень частое выделение/удаление памяти. Это типо для борьбы с дефрагментацией :)
>Добавление происходит быстрей
>удаления, что естественно ведет к постоянному росту списка, что в конечном
>счете может привести к переполнению памяти. Соответственно вопрос, как этого избежать?сливать в свап и увеличивать свап, добавить озу, еще добавить озу, юзать темповые файлы, и в конце концов если есть возможность свободно менять код - переписать дизайн.
>Можно ли, например, задать программе (внутри самой программы) какое-то ограничение на
>объем доступной памяти, и при этом, соответственно, определить момент, когда этот
>предел будет достигнут (в этом случае можно было бы делать паузу
>и ждать, пока снова не появится достаточно доступной памяти)?легко, можно даже снаружи перед запуском задать объем памяти для процесса:
man ulimit ключ -v
дальше если malloc вернет NULL, значит не может выделить, пора возвращать выделенное =)
внутри программы системными вызовами getrlimit, getrusage, setrlimit.
>Кроме того, я пытался использовать процессы вместо потоков и разделяемую память, но
>в этом случае ограничение на объем доступной разделяемой памяти оказался слишком
>маленький (не то 32Мб, не то 64). Может кто-нибудь знает, как
>увеличить это ограничение хотя бы до 2Гб?видимо ulimit -l :)
>
>И забыл сказать. Программа написана под Red Hat Enterprise Linux 3.0 (ядро
>linux 2.4.21)достаточно ядра, редкая софтина юзает особые уличный фичи всяких энтерпрайзов и т.п. :)
>[оверквотинг удален]
>участки памяти всегда разной длины, что ведет к дефрагментации и в
>конечном счете доступно будет гораздо меньше памяти, чем действительно свободно.
>
>Кроме того, я пытался использовать процессы вместо потоков и разделяемую память, но
>в этом случае ограничение на объем доступной разделяемой памяти оказался слишком
>маленький (не то 32Мб, не то 64). Может кто-нибудь знает, как
>увеличить это ограничение хотя бы до 2Гб?
>
>И забыл сказать. Программа написана под Red Hat Enterprise Linux 3.0 (ядро
>linux 2.4.21)Основная ошибка постоянное выделение и высвобождение памяти (сам с таким сталкивался )
Необходимо выделить память для фиксированного количества данных, и по мере необходимости увеличивать, тогда все будет работать корректно.
>удаления, что естественно ведет к постоянному росту списка, что в конечном
>счете может привести к переполнению памяти. Соответственно вопрос, как этого избежать?
>Можно ли, например, задать программе (внутри самой программы) какое-то ограничение на
>объем доступной памяти, и при этом, соответственно, определить момент, когда этот
>предел будет достигнут (в этом случае можно было бы делать паузу
>и ждать, пока снова не появится достаточно доступной памяти)? Просто подсчитывать
>количество выделенной памяти ведь не подойдет, так как выделяемые и освобождаемые
>участки памяти всегда разной длины, что ведет к дефрагментации и в
>конечном счете доступно будет гораздо меньше памяти, чем действительно свободно.Программа играет роль буфера, сглаживающего пиковые нагрузки? Если так, видимо на стадии обработки допущен просчет. Как следует из последующих постов - это может быть неоптимальная конфигурация БД. Если не применять никаких оптимизаций, то скорость работы по INSERT запросам на однодисковой (не RAID) платформе где-то 200-300 запросов в секунду, и с ростом этой таблицы будет только уменьшаться. Я говорю про MySQL, но, думаю, что и для других БД это будет характерно - для БД важна пропускная способность диска, и скорость обработки мелких запросов.
>Кроме того, я пытался использовать процессы вместо потоков и разделяемую память, но
>в этом случае ограничение на объем доступной разделяемой памяти оказался слишком
>маленький (не то 32Мб, не то 64). Может кто-нибудь знает, как
>увеличить это ограничение хотя бы до 2Гб?Возникает впечатление, что вы пытаетесь бороться с последствиями проблемы, а не самой проблемой,.
По фрагментации памят можно предложить сегментировать её самостоятельно на большие фрагменты: обрабатываемые буфера протяженностью более листа памяти разбивать на секции по размеру системного листа. Если динамический список сделать циклическим, то можно будет по превышению объема памяти свыше установленного лимита - сбрасывать данные на диск, затем их считывать обратно. Естественно, если этот диск уже испытывает значительную нагрузку, то этим проблему можно только усугубить.
С точки зрения постановки задачи более ничего не приходит в голову.