Форум русскоязычного сообщества Ubuntu


Увидели сообщение с непонятной ссылкой, спам, непристойность или оскорбление?
Воспользуйтесь ссылкой «Сообщить модератору» рядом с сообщением!

Автор Тема: Постоянный рост занимаемой памяти приложением  (Прочитано 1632 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн @rch1tect0r

  • Автор темы
  • Новичок
  • *
  • Сообщений: 14
    • Просмотр профиля
Добрый день.
Я написал приложение на С++, которое должно работать в режиме 24/7, но больше 2х суток оно не работает, т.к. постепенно оно съедает всю виртуальную, а затем и физическую оперативную память(6Гб) :o В результате ядро убивает это приложение и его требуется перезапустить.

Я пробовал использовать Valgrind чтобы найти утечки памяти и я их нашёл(до этого программа работала только 12-14 часов). Сейчас Valgrind говорит, что никаких утечек памяти нет, но тем не менее я вижу стабильный рост потребляемой оперативной памяти.

Пробовал использовать malloc_trim(0), чтобы возвращать ОС занимаемую память, но кажется решение не слишком эффективное, хотя и продлевает время работы программы.

Приложение многопоточное и достаточно большое, так что выложить его для просмотра кода вряд ли получится, поэтому вопрос что ещё можно предпринять, чтобы понять, что я неправильно написал и требуется исправить?

Оффлайн aSmile

  • Активист
  • *
  • Сообщений: 755
    • Просмотр профиля
Везде, где используешь new используй умные указатели. Тоже писал многопоточный сервер для работы 24/7 - использовал ТОЛЬКО умные указатели (в моем случае это были boost::shared_ptr), и никаких утечек не было (главное циклические ссылки не делать)

Оффлайн Peter_I

  • Старожил
  • *
  • Сообщений: 3124
    • Просмотр профиля
Для new надо использовать free(), на каждое выделение - соответствующее освобождение перед выходом из подпрограммы
или закрытием потока.
Пётр.

Оффлайн aSmile

  • Активист
  • *
  • Сообщений: 755
    • Просмотр профиля
Для new надо использовать free(), на каждое выделение - соответствующее освобождение перед выходом из подпрограммы
или закрытием потока.
free - это для malloc. Для new - delete :)

Оффлайн @rch1tect0r

  • Автор темы
  • Новичок
  • *
  • Сообщений: 14
    • Просмотр профиля
Спасибо за советы.
Но использовать умные указатели у меня не получится в виду наличия обусловленной логикой цикличности между отдельными классами.

Valgrind утверждает, что утечек памяти нет, но тем не менее программа потихоньку занимает всё больше и больше оперативной памяти.

Мне кажется, я просто не знаю на что ещё нужно обратить внимание в такого классах задачах, из-за чего программа может понемногу добирать память, а анализаторы при этом не будут показывать какие-то сообщения об ошибках...  :-\
« Последнее редактирование: 21 Марта 2016, 17:04:30 от @rch1tect0r »

Оффлайн Peter_I

  • Старожил
  • *
  • Сообщений: 3124
    • Просмотр профиля
Для new надо использовать free(), на каждое выделение - соответствующее освобождение перед выходом из подпрограммы
или закрытием потока.
free - это для malloc. Для new - delete :)
Да, виноват, перепутал. Я, конечно, в программе на Qt использую delete.
Пётр.

Оффлайн alsoijw

  • Старожил
  • *
  • Сообщений: 4062
  • Fedora 25 GNOME 3 amd64
    • Просмотр профиля
Спасибо за советы.
Но использовать умные указатели у меня не получится в виду наличия обусловленной логикой цикличности между отдельными классами.
Идея написать своё умный указатель не рассматривалась? Это не так то уж и сложно. Или перейти на язык в котором нет необходимости следить за выделением памяти?
Мало видеть нам начало - надо видеть и конец. Если видишь ты создание - значит где-то есть ТВОРЕЦ
Многие жалуются: геометрия в жизни не пригодилась. Ямб от хорея им приходится отличать ежедневно?

Оффлайн aSmile

  • Активист
  • *
  • Сообщений: 755
    • Просмотр профиля
Но использовать умные указатели у меня не получится в виду наличия обусловленной логикой цикличности между отдельными классами.

Цикличность между классами умным указателям не помеха. Главное, чтобы не было цикличности между объектами. Типа объект a содержит в себе ссылку на объект b, и объект b содержит в себе ссылку на объект a

Пользователь решил продолжить мысль [time]22 Март 2016, 13:45:58[/time]:
И еще, возможно у тебя действительно нет утечек, но ошибка где-то в логике - ты не удаляешь данные, когда они уже не нужны. Указатели на эти данные живи, память не течет, но в действительности они уже не актуальны и их надо удалить. Найти такие места сложнее - тут уже надо периодически печатать в лог какую-то статистику (размеры динамических массивов, очередей и т.п.)
« Последнее редактирование: 22 Марта 2016, 12:50:39 от aSmile »

Оффлайн unimix

  • Активист
  • *
  • Сообщений: 537
    • Просмотр профиля
Но использовать умные указатели у меня не получится в виду наличия обусловленной логикой цикличности между отдельными классами.
Цикличность между классами умным указателям не помеха. Главное, чтобы не было цикличности между объектами. Типа объект a содержит в себе ссылку на объект b, и объект b содержит в себе ссылку на объект a

В чём разница между цикличностью между классами и между объектами? Да и вроде есть умные ссылки против цикличности.

А по теме (без умных ссылок и сборщиков мусора):
- При создании объекта через new и удалении ссылки на объект удалять и сам объект через delete. (На каждый new должен быть delete).
- Стоит обращать внимание на области видимости ссылки (внутри функции создана временная ссылка с созданным временным объектом, но по завершению функции объект не удаляется).
- Если в классе в свойствах используются ссылки, а объекты создаются в конструкторе или функциях класса, то удалять объекты в деструкторе класса или в соответствующей функции. (В каком классе создаётся объект, в том классе он и удаляется).
« Последнее редактирование: 22 Марта 2016, 13:15:27 от unimix »

Оффлайн aSmile

  • Активист
  • *
  • Сообщений: 755
    • Просмотр профиля
В чём разница между цикличностью между классами и между объектами? Да и вроде есть умные ссылки против цикличности.

Код: (c++) [Выделить]
class B;

class A {
public:
 B* b;
}

class B {
public:
 A* a;
}

int main() {
 A a1;
 B b1,b2;
 a1.b = &b2;
 b1.a = &a1;
 b2.a = nullptr;
 // Классы зависят друг от друга, но цилкической зависимости между объектами нет. Её можно создать b2.a = &a1
}

А умные ссылки против циклических зависимостей объектов - навладеющие, например boost::weak_ptr

Оффлайн unimix

  • Активист
  • *
  • Сообщений: 537
    • Просмотр профиля
aSmile, понял, про что имелось ввиду.

Кстати, в С++11 умные указатели уже в стандартной библиотеке.

Оффлайн @rch1tect0r

  • Автор темы
  • Новичок
  • *
  • Сообщений: 14
    • Просмотр профиля
И еще, возможно у тебя действительно нет утечек, но ошибка где-то в логике - ты не удаляешь данные, когда они уже не нужны. Указатели на эти данные живи, память не течет, но в действительности они уже не актуальны и их надо удалить. Найти такие места сложнее - тут уже надо периодически печатать в лог какую-то статистику (размеры динамических массивов, очередей и т.п.)

Хмм... значит видимо в этом направлении и надо двигаться. Я сейчас пытаюсь заменить часть настоящих классов на "фейковые", которые бы имели такой же внешний интерфейс, но внутри не выполняли какие-то расчёты и не имели буферов, чтобы хоть как-то постараться сузить круг поиска проблем.

Оффлайн unimix

  • Активист
  • *
  • Сообщений: 537
    • Просмотр профиля
@rch1tect0r, не проще ли для начала выводить статистику создания и удаления объектов из конструкторов и деструкторов? Потом посчитать каких объектов создаётся больше, чем удаляется.

Оффлайн Peter_I

  • Старожил
  • *
  • Сообщений: 3124
    • Просмотр профиля
unimix,
Никогда этого не делал. Автор и так знает, подо что он выделяет память
и точно также должен её вернуть в деструкторе. Если программа графическая,
то надо самому обязательно освобождать память, выделенную под объекты,
не имеющие родителя, а для имеющих это сделает деструктор родителя.
Пётр.

Оффлайн @rch1tect0r

  • Автор темы
  • Новичок
  • *
  • Сообщений: 14
    • Просмотр профиля
@rch1tect0r, не проще ли для начала выводить статистику создания и удаления объектов из конструкторов и деструкторов? Потом посчитать каких объектов создаётся больше, чем удаляется.

Согласно логу всё создаётся и разрушается так как должно.
А те объекты, которые попадают в накопительные буферы, создаются и разрушаются с такой частотой, что лог станет весом в гигабайт за пару минут. Пользы от такого большого лога получается не очень много.
Повторные вызовы конструкторов исключены, потому что я везде для блокировки такого поведения использую boost::unique_lock. Лог тоже подтверждает это. Деструкторы тоже вызываются только один раз.

В особо критичных местах прописано даже вот такое логирование, чтобы убедиться что нет повторных запусков:
    Logger::getInstance().info("destructor begin");
   
    /*some actions*/
   
    Logger::getInstance().info("destructor end");

После долгой замены настоящих классов на мнимые нашёл одну закономерность, которая привела к велосипеду, который я написал для перемещение из одного std::list в другой. Произвёл замену моего велосипеда на стандартный метод splice и у меня снизилось выделение памяти.
Теперь только время покажет правильно ли я нашёл проблему или осталось ещё где-то что-то неприятное.

 

Страница сгенерирована за 0.054 секунд. Запросов: 25.