FANN: утечка памяти при обучении ANN с использованием данных, прочитанных из нескольких файлов

Простым решением является создание скрипта start.sh, который запускает Java через nohup, а затем сохраняет PID в файл:

nohup java -jar myapplication.jar > log.txt 2> errors.txt < /dev/null &
PID=$!
echo $PID > pid.txt

Тогда ваш стоп-скрипт stop.sh будет читать PID из файл и убить приложение:

PID=$(cat pid.txt)
kill $PID

Конечно, я не рассмотрел некоторые детали, например, проверить, существует ли процесс и удалить pid.txt, если вы закончили.

1
задан daedsidog 4 March 2019 в 01:30
поделиться

2 ответа

Поскольку требуется вызвать fann_destroy_train_data, вы можете использовать C ++ и RAII, используя следующую обертку:

struct fann_wrapper
{
   fann_train_data *td;
   fann_wrapper(fann_train_data* p) : td(p) {}
   ~fann_wrapper() { fann_destroy_train_data(td); }
};
//...
for (int i = 1; i <= epochs; ++i) {
    for (std::vector<std::filesystem::path>::iterator it = batchFiles.begin(); it != batchFiles.end(); ++it) {
        struct fann_train_data *data = fann_read_train_from_file(it->string().c_str());

        // the next line ensures that fann_destroy_train_data is called
        fann_wrapper fw(data);

        fann_shuffle_train_data(data);
        float error = fann_train_epoch(ann, data);
    }  // when this curly brace is encountered, the fann_destroy_train_data is always called
}  

fann_wrapper просто содержит указатель fain_train_data, и при уничтожении fann_wrapper, fann_train_data уничтожен.

Причина, по которой это намного безопаснее, чем метод C, заключается в том, что может быть выдано возможное исключение (по любой причине). Если выдается исключение, то fann_train_data будет всегда уничтожаться при использовании fann_wrapper. Эту гарантию нельзя сделать с помощью метода C, поскольку исключение полностью пропустит любую строку, содержащую fann_destroy_train_data.

Пример:

for (int i = 1; i <= epochs; ++i) {
    for (std::vector<std::filesystem::path>::iterator it = batchFiles.begin(); it != batchFiles.end(); ++it) {
        struct fann_train_data *data = fann_read_train_from_file(it->string().c_str());
        fann_shuffle_train_data(data);
        float error = fann_train_epoch(ann, data);

        fann_destroy_train_data(data); // this line is not executed if an exception is thrown above, thus a memory leak
    }
}  

Вот почему RAII является важной концепцией в C ++. Ресурсы будут очищаться автоматически, независимо от причины выхода исполняемого блока кода (генерируется исключение, выполняется return и т. Д.).

0
ответ дан PaulMcKenzie 4 March 2019 в 01:30
поделиться

В C ++ память автоматически освобождается, когда управляющий ею объект выходит из области видимости. (Предполагая, что класс был написан правильно.) Это называется RAII .

Но FANN представляет C API, а не C ++ API. В C вам нужно вручную освободить память, когда вы закончите с ней. Более того, когда библиотека C создает объект для вас, обычно требуется, чтобы вы сказали ему, когда вы закончите с объектом. Библиотека не может самостоятельно определить, когда ресурсы объекта должны быть освобождены.

Соглашение состоит в том, что всякий раз, когда C API предоставляет вам функцию, подобную struct foo* create_foo(), вы должны искать соответствующую функцию, подобную void free_foo(struct foo* f). Это симметрично.

В вашем случае, как первоначально отмечал PaulMcKenzie, вам нужно void fann_destroy_train_data(struct fann_train_data * train_data). Из документации , выделено мое:

Уничтожает обучающие данные и должным образом освобождает все связанные данные. Обязательно вызывайте эту функцию после завершения использования обучающих данных.

0
ответ дан Maxpm 4 March 2019 в 01:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: