Почему этот простой код libpqxx пропускает память?

Недавно я написал приложение, которое получает доступ к базе данных Postgres через libpqxx, и оно сильно теряет память. Даже эта простая тестовая программа, основанная на примере http://pqxx.org/devprojects/libpqxx/doc/4.0/html/Reference/a00001.html Утечки, как нет завтра.

(Изменить: я добавил вызовы commit () и clear () в ответ на предложения. Та же утечка.)

#include <iostream>
#include <pqxx/pqxx>
#include <string>
#include <stdio.h>

int main()
{
try
{
pqxx::connection c("user=postgres");

int i = 0;
while(true)
{
pqxx::work w(c);
pqxx::result r = w.exec("SELECT 1");
w.commit();

i++;
if ( i % 1000 == 0 )
printf( "Cycle %d\n", i );

r.clear();
} //while
} //try
catch (const std::exception &e)
{
std::cerr << e.what() << std::endl;
return 1;
} //catch
} //main

После примерно 75 000 циклов цикла top показывает 206 МБ использования виртуальной памяти и продолжает расти. Я запустил аналогичную тестовую программу с 5000 циклами через valgrind и получил это:

==1647== 13,732,155 (219,868 direct, 13,512,287 indirect) bytes in 4,997 blocks are definitely lost in loss record 12 of 12
==1647==    at 0x40060D5: operator new(unsigned int) (vg_replace_malloc.c:214)
==1647==    by 0x404C0A9: pqxx::result::result(pg_result*, int, std::string const&, int) (in /usr/lib/libpqxx-4.0.so)
==1647==    by 0x40309EF: pqxx::connection_base::make_result(pg_result*, std::string const&) (in /usr/lib/libpqxx-4.0.so)
==1647==    by 0x4036D65: ??? (in /usr/lib/libpqxx-4.0.so)
==1647==    by 0x405EFD6: pqxx::transaction_base::DirectExec(char const*, int) (in /usr/lib/libpqxx-4.0.so)
==1647==    by 0x40416EA: pqxx::dbtransaction::do_exec(char const*) (in /usr/lib/libpqxx-4.0.so)
==1647==    by 0x40618FA: pqxx::transaction_base::exec(std::string const&, std::string const&) (in /usr/lib/libpqxx-4.0.so)
==1647==    by 0x80498F8: main (dbtest.cpp:21)

Есть идеи, что происходит? Очень трудно согласиться с тем, что широко используемая библиотека, такая как libpqxx, будет иметь такую ​​серьезную ошибку, так что я могу сделать здесь неправильно?

Детали конфигурации:

  • ОС: Linux 2.6.18-238.el5
  • gcc версия 4.4.0
  • libpqxx 4.0
  • Postgres 9,2

(Окончательное редактирование: мне было проще заменить libpqxx на libpq, чем продолжать расследовать эту утечку памяти.)

4

Решение

Я не мог воспроизвести вашу проблему.

Ни с libpqxx-2.6.9, ни с libpqxx-4.0.1 (в настоящее время текущая стабильная версия).

  • Debian Linux 2.6.32
  • gcc версия 4.4.5
  • libpq5 8.4.17
  • libpqxx 4.0.1
  • libstdc ++ 6.4.4
  • Postgres 8,4

Использование памяти постоянно.

$ valgrind —tool = memcheck run.sh
[…] Цикл 35000
Цикл 36000
^ C == 18420 ==
== 18420 == РЕЗЮМЕ КАРТЫ:
== 18420 == используется на выходе: 0 байтов в 0 блоках
== 18420 == общее использование кучи: 0 выделений, 0 освобождений, 0 выделенных байтов
== 18420 ==
== 18420 == Все блоки кучи были освобождены — утечки невозможны

Я бы проверил, если у вас есть проблемы с различными установками библиотек, которые вы используете. Например, вы ссылаетесь на libpqxx-4.0, но позже, когда вы запускаете программу, вы используете другую версию.

$ ldd client
linux-gate.so.1 => (0xb7776000)
libpqxx-4.0.so => ​​не найден
libstdc ++. so.6 => /usr/lib/libstdc++.so.6 (0xb7669000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb764a000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7503000)
libpthread.so.0 => /lib/i686/cmov/libpthread.so.0 (0xb74ea000)
libm.so.6 => /lib/i686/cmov/libm.so.6 (0xb74c4000)
/lib/ld-linux.so.2 (0xb7777000)

Поскольку я скачал и установил libpqxx-4.0.1 вручную, я должен установить LD_LIBRARY_PATH явно, так как я не установил его ниже /usr/local/, Если разные версии установлены в /usr/localПочисти там раньше.

В вашем случае (используя ldd) libpqxx должен указывать на версию, которую вы скомпилировали и установили. Убедитесь, что в вашей системе установлен только один libpqxx.

Я использовал это Makefile

CPPFLAGS + = -I / home / dev / data / src / cpp / libpqxx-4.0.1 / install / include
LDFLAGS + = -L / home / dev / data / src / cpp / libpqxx-4.0.1 / install / lib -lpqxx -lstdc ++

клиент: client.o

и libpqxx был построен с

./ configure —prefix = / home / dev / data / src / cpp / libpqxx-4.0.1 / install —enable-shared
делать
сделать установку

и я запустил программу, используя

LD_LIBRARY_PATH = $ LD_LIBRARY_PATH: /home/dev/data/src/cpp/libpqxx-4.0.1/install/lib client

3

Другие решения

Вероятно, что pqxx :: result вызывает утечку памяти. Попробуйте добавить:

r.clear();

Это по крайней мере уменьшит утечку.

#include <iostream>
#include <pqxx/pqxx>
#include <string>
#include <stdio.h>

int main()
{
try
{
pqxx::connection c("user=postgres");

int i = 0;

while(true)
{
pqxx::work w(c);
pqxx::result r = w.exec("SELECT 1");

i++;
if ( i % 1000 == 0 )
printf( "Cycle %d\n", i );

r.clear();
} //while
} //try
catch (const std::exception &e)
{
std::cerr << e.what() << std::endl;
return 1;
} //catch
} //main
1

Попробуйте объявить pqxx :: result r без пока. И звони внутрь, как делаешь. Потому что для каждого цикла while вы создаете объект pqxx :: result. Таким образом, вы создадите только один объект для всего цикла, чтобы заряжать и очищать в каждом цикле:

#include <iostream>
#include <pqxx/pqxx>
#include <string>
#include <stdio.h>

int main()
{
try
{
pqxx::connection c("user=postgres");

int i = 0;
pqxx::result r;
while(true)
{
pqxx::work w(c);
r = w.exec("SELECT 1");
w.commit();

i++;
if ( i % 1000 == 0 )
printf( "Cycle %d\n", i );

r.clear();
} //while
} //try
catch (const std::exception &e)
{
std::cerr << e.what() << std::endl;
return 1;
} //catch
} //main

Или, что еще лучше, создайте метод для вызова в каждом цикле while, поэтому после завершения каждого вызова метода временный объект исчезнет.

main()
{
...
while()
{
...
method_to_call_pqxx();
}
}
1
По вопросам рекламы [email protected]