ecCodes (библиотека чтения grib) не освобождает память
Я использую в своем проекте , и я столкнулся с проблемой, библиотеку ecCodesзаключающейся в том, что память не освобождается между чтением файлов.
Минимальный пример, представляющий проблему, таков (и в основном представляет собой комбинацию этих двух примеров использования API библиотеки [ ](https://confluence.ecmwf.int/display/ECC/grib_get_keys) [2]:
#include <string>
#include <vector>
#include <iostream>
#include "eccodes.h"
int main() {
std::string filenames[] = {"../data/era5_model.grib", "../data/era5_model2.grib", "../data/era5_model3.grib",
"../data/era5_model4.grib"};
std::vector<long> vec = {};
for (auto & filename : filenames) {
FILE* f = fopen(filename.c_str(), "r");
int err = 0;
codes_handle* h;
while ((h = codes_handle_new_from_file(nullptr, f, PRODUCT_GRIB, &err)) != nullptr) {
long k1 = 0;
err = codes_get_long(h, "level", &k1);
vec.push_back(k1);
}
codes_handle_delete(h);
fclose(f);
}
std::cout << vec[52];
return 0;
}
В этом примере программа считывает 4 идентичных файла ERA5, каждый размером 1,5 ГБ. Перед открытием нового файла предыдущий закрывается с помощью code_handle_delete () и fclose (). Таким образом, ожидается, что использование памяти останется на уровне около 1,5 ГБ. Однако на самом деле использование памяти постоянно увеличивается примерно до 6,5 ГБ и освобождается при закрытии программы (см. Снимок экрана ниже).
Этот конкретный пример был запущен на CLion с CMake (конфигурация выпуска), но проблема возникает с любой другой конфигурацией, а также в моем другом проекте Rust, который вызывает ecCodes с FFI.
Библиотека кажется хорошо протестированной и поддерживаемой, поэтому маловероятно, что это ошибка библиотеки. Следовательно, это ожидаемое поведение или мой код неправильный? Если второе, как я могу это исправить?
Я использую Ubuntu 21.04 и ecCodes 2.20.0, установленные с apt
1 ответ
Я связался с авторами библиотеки и понял, что недостаточно внимательно прочитал этот пример .
Чтобы ecCodes правильно освободили память
codes_handle
следует удалять каждый раз, когда он создается (аналогично тому, как вы должны освобождать память каждый раз, когда вы ее выделяете). Поэтому в моем примере
codes_handle_delete()
должен быть ВНУТРИ
while
петля:
while ((h = codes_handle_new_from_file(nullptr, f, PRODUCT_GRIB, &err)) != nullptr) {
long k1 = 0;
err = codes_get_long(h, "level", &k1);
vec.push_back(k1);
codes_handle_delete(h);
}
После этого изменения использование памяти практически незаметно.