localtime_r потребляет немного памяти перед выходом из программы

Я использую массив valgrind для отслеживания использования памяти на последнем этапе перед выходом из программы и нашел

  • js::DateTimeInfo::updateTimeZoneAdjustment() (DateTime.cpp:19)

который вызывает localtime_r и потребляет немного памяти.

16 ComputeLocalTime(time_t local, struct tm *ptm)
17 {
18 #ifdef HAVE_LOCALTIME_R
19     return localtime_r(&local, ptm);
20 #else
21     struct tm *otm = localtime(&local);
22     if (!otm)

ms_print последнего снимка из массива valgrind

427711 --------------------------------------------------------------------------------
427712   n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
427713 --------------------------------------------------------------------------------
427714  95 15,049,552,789              256              165            91            0
427715 64.45% (165B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
427716 ->36.72% (94B) 0x37AFA9EA6A: __tzfile_read (in /lib64/libc-2.12.so)
427717 | ->36.72% (94B) 0x37AFA9DC02: tzset_internal (in /lib64/libc-2.12.so)
427718 |   ->36.72% (94B) 0x37AFA9DD67: __tz_convert (in /lib64/libc-2.12.so)
427719 |     ->36.72% (94B) 0x4CAE552: js::DateTimeInfo::updateTimeZoneAdjustment() (DateTime.cpp:19)
427720 |       ->36.72% (94B) 0x4D814C9: JSRuntime::JSRuntime(JSUseHelperThreads) (jsapi.cpp:856)
427721 |         ->36.72% (94B) 0x4D8B71A: JS_NewRuntime(unsigned int, JSUseHelperThreads) (Utility.h:491)
427722 |           ->36.72% (94B) 0x40162A: main (js.cc:58)
427723 |
427724 ->15.62% (40B) 0x37AFA9D0D0: __tzstring (in /lib64/libc-2.12.so)
427725 | ->15.62% (40B) 0x37AFA9EF99: __tzfile_read (in /lib64/libc-2.12.so)
427726 |   ->15.62% (40B) 0x37AFA9DC02: tzset_internal (in /lib64/libc-2.12.so)
427727 |     ->15.62% (40B) 0x37AFA9DD67: __tz_convert (in /lib64/libc-2.12.so)
427728 |       ->15.62% (40B) 0x4CAE552: js::DateTimeInfo::updateTimeZoneAdjustment() (DateTime.cpp:19)
427729 |         ->15.62% (40B) 0x4D814C9: JSRuntime::JSRuntime(JSUseHelperThreads) (jsapi.cpp:856)
427730 |           ->15.62% (40B) 0x4D8B71A: JS_NewRuntime(unsigned int, JSUseHelperThreads) (Utility.h:491)
427731 |             ->15.62% (40B) 0x40162A: main (js.cc:58)
427732 |
427733 ->05.86% (15B) 0x37AFA81170: strdup (in /lib64/libc-2.12.so)
427734 | ->05.86% (15B) 0x37AFA9DBEF: tzset_internal (in /lib64/libc-2.12.so)
427735 |   ->05.86% (15B) 0x37AFA9DD67: __tz_convert (in /lib64/libc-2.12.so)
427736 |     ->05.86% (15B) 0x4CAE552: js::DateTimeInfo::updateTimeZoneAdjustment() (DateTime.cpp:19)
427737 |       ->05.86% (15B) 0x4D814C9: JSRuntime::JSRuntime(JSUseHelperThreads) (jsapi.cpp:856)
427738 |         ->05.86% (15B) 0x4D8B71A: JS_NewRuntime(unsigned int, JSUseHelperThreads) (Utility.h:491)
427739 |           ->05.86% (15B) 0x40162A: main (js.cc:58)
427740 |
427741 ->03.12% (8B) 0x4015C6: allocate() (js.cc:41)
427742 | ->03.12% (8B) 0x40187E: main (js.cc:114)
427743 |
427744 ->03.12% (8B) 0x4015E2: allocate() (js.cc:43)
427745 | ->03.12% (8B) 0x40187E: main (js.cc:114)
427746 |
427747 ->00.00% (0B) 0x4D8B3E8: JSRuntime::init(unsigned int) (Utility.h:154)
427748 | ->00.00% (0B) 0x4D8B73B: JS_NewRuntime(unsigned int, JSUseHelperThreads) (jsapi.cpp:1121)
427749 |   ->00.00% (0B) 0x40162A: main (js.cc:58)
427750 |
427751 ->00.00% (0B) 0x4D8B435: JSRuntime::init(unsigned int) (Utility.h:154)
427752 | ->00.00% (0B) 0x4D8B73B: JS_NewRuntime(unsigned int, JSUseHelperThreads) (jsapi.cpp:1121)
427753 |   ->00.00% (0B) 0x40162A: main (js.cc:58)

Есть ли способ освободить это до выхода из моей программы? (насколько я понимаю, он будет очищен при выходе из программы)


person Denny    schedule 08.05.2014    source источник
comment
Я бегло взглянул на функцию __tzfile_read в исходном коде glibc. Похоже на ошибку в их коде. Утечка достижима или недоступна? Если вы вызовете localtime_r дважды, увеличится ли объем утечки памяти?   -  person kec    schedule 08.05.2014


Ответы (1)


Почему localtime_r() выделяет память?

Функции даты/времени в библиотеке времени выполнения C должны знать различную информацию о часовых поясах, например, когда начинается и заканчивается переход на летнее время и т. д. Они хранятся в так называемом Файл часового пояса.

При первом вызове какой-либо связанной функции даты/времени этот файл необходимо загрузить, проанализировать и сохранить его данные где-то, чтобы дальнейшие вызовы этих функций снова не повлекли за собой такое же наказание. Распределения, которые вы видите, связаны с этим.

Так это утечка памяти?

Эта память выделяется, но никогда не освобождается во время выполнения программы, поэтому ее можно считать утечкой памяти. Но на самом деле это не ошибка, потому что это сознательное решение авторов библиотеки.

Как я писал выше, данные загружаются один раз и с тех пор (возможно) используются до конца выполнения программы. Они будут освобождены только в самом конце, до завершения процесса. На самом деле в libc есть много структур с одинаковым шаблоном использования.

Вот они и подумали, что вместо того, чтобы перебирать все выделения по очереди, освобождая память, они просто оставляют ее там, потому что в следующую миллисекунду процесс все равно завершится и ядро ​​все равно вернет обратно всю выделенную память (и гораздо быстрее, при этом сразу всю кучу).

Так что нет никакого способа избавиться от этого?

Не совсем, есть! Но не для обычного пользователя... Как говорится в документации Valgrind:

Авторы glibc поняли, что такое поведение заставляет средства проверки утечек, такие как Valgrind, ложно сообщать об утечках в glibc, когда проверка на утечку выполняется на выходе. Чтобы избежать этого, они предоставили подпрограмму под названием __libc_freeres специально для того, чтобы заставить glibc освободить всю выделенную память.

Как и ожидалось, подпрограммы, работающие с файлом часового пояса, действительно используют этот механизм «freeres», например. time/tzfile.c:

libc_freeres_ptr (static time_t *transitions);

Valgrind вызывает эту подпрограмму перед end, поэтому, если вы запустите ее с помощью инструмента memcheck (по умолчанию), вы не увидите ни одной из этих «утечек». Они должны исчезнуть даже для вашей программы, вероятно, это просто massif, который перечисляет распределения, когда они происходят, а не после того, как все закончилось.

У вас может быть успешный вызов __libc_freeres самостоятельно, но это также может привести к сбою, потому что libc все еще выполняет некоторую внутреннюю обработку после завершения пользовательской функции main(), и вы можете преждевременно освободить ее внутренние структуры.

person Yirkha    schedule 08.05.2014