FAT fs를 사용하여 SD에 파일을 쓸 때 메모리 누수가 발생할 수 있습니다.

FAT fs를 사용하여 SD에 파일을 쓸 때 메모리 누수가 발생할 수 있습니다.

SD 카드 슬롯이 있는 HI3516A SoC 기반 IP 카메라가 있습니다. 카메라의 운영 체제는 사용자 정의 3.4.45 Linux 커널입니다. 모든 것이 잘 작동하지만 Azure의 원격 저장소에 있는 카메라의 비디오 복사본이 필요하므로 내부 RTP 스트림을 캡처하여 세그먼트로 분할하고 세그먼트를 SD 카드에 쓰는 프로그램을 C로 작성했습니다. 내 Azure Storage로 전송됩니다.

64GB SD 카드를 카메라에 마운트하고 FAT fs를 생성한 후 /mnt/sd_card에 마운트했습니다. 내 프로그램은 예상대로 작동했지만 정상적으로 작동한 지 1~3일 후에 카메라의 RAM이 모두 어딘가에서 사라진 것을 발견했습니다.

먼저 프로그램에 메모리 누수가 있는 것을 확인하고 다음 명령으로 프로그램을 종료했습니다.

kill -S SIGKILL 1223

그러나 메모리는 시스템으로 반환되지 않습니다. 제 생각에는 이상한 행동입니다. 며칠 동안 버그를 수정한 후 갑자기 SD 카드를 마운트 해제했고 모든 메모리가 시스템에 반환되었다는 사실을 발견했습니다. 이제 내 프로그램의 파일 생성 부분에 문제가 있다고 판단했습니다. 이 상황을 테스트하기 위해 다음 프로그램을 작성했습니다.

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <limits.h>
#include <inttypes.h>
#include <time.h>

#define KB 1024
#define MB KB * 1024
#define GB MB * 1024


static void print_msg(const char *fmt, ...) {
    va_list args;
    time_t timer = time(NULL);

    printf("%s\t", ctime(&timer));

    va_start(args, fmt);
    vfprintf(stdout, fmt, args);
    va_end(args);
}

static int generate_file(const char *dest_fname, const size_t file_size) {
    char buffer[BUFSIZ];
    const char *source_fname = "/dev/urandom";
    size_t bytes_to_operate, avaliable_bytes = file_size;
    int bytes_readed, bytes_writed, source_fd = -1, dest_fd = -1, rc = EXIT_SUCCESS;


    source_fd = open(source_fname, O_RDONLY);
    if (source_fd < 0) {
        printf("Can't open source file '%s': %s.\n", source_fname, strerror(errno));
        rc = EXIT_FAILURE;
        goto end;
    }

    dest_fd = open(dest_fname, O_CREAT | O_WRONLY | O_TRUNC, 0666);
    if (dest_fd < 0) {
        printf("Can't open destination file '%s': %s.\n", dest_fname, strerror(errno));
        rc = EXIT_FAILURE;
        goto end;
    }

    bytes_to_operate = avaliable_bytes - BUFSIZ;

    print_msg("Write random data to file\n");
    while(avaliable_bytes > 0) {
        bytes_to_operate = (avaliable_bytes > BUFSIZ) 
                ? BUFSIZ
                : avaliable_bytes;

        bytes_readed = read(source_fd, buffer, bytes_to_operate);
        if (bytes_readed < 0) {
            printf("Error while reading data from '%s': %s", source_fname,
                    strerror(errno));
            rc = EXIT_FAILURE;
            goto end;
        }

        if (bytes_readed != bytes_to_operate) {
            // don't read write more than read
            bytes_to_operate = bytes_readed;
        }

        bytes_writed = write(dest_fd, buffer, bytes_to_operate);

        if (bytes_writed < 0) {
            printf("Error while writing data to '%s': %s", dest_fname,
                    strerror(errno));
            rc = EXIT_FAILURE;
            goto end;
        }

        avaliable_bytes -= bytes_writed;
    }

end:
    print_msg("Close file\n");                
    close(source_fd);
    close(dest_fd);

    return rc;
}

static void generate_fpath(char *out, const char *dest_path, uint16_t index) {
    snprintf(out, PATH_MAX, "%s/file_%"SCNu16, dest_path, index);
}

int main(int argc, char** argv) {

    size_t file_size;
    const char *dest_path = argv[3];
    char fpath[PATH_MAX];
    uint16_t del_index = 0, cur_index = 0;

    switch(argv[2][0]) {
        case 'K':
            file_size = atoi(argv[1]) * KB;
            break;
        case 'M':
            file_size = atoi(argv[1]) * MB;
            break;
        default:
            file_size = atoi(argv[1]);
            break;
    } 

    print_msg("Generate files of size %s%s to %s\n", argv[1], argv[2], argv[3]);

    while (cur_index < UINT16_MAX) {
        generate_fpath(fpath, dest_path, cur_index);
        generate_file(fpath, file_size);
        printf("Created file %s\n", fpath);
        cur_index++;
        del_index++;
        sleep(1);
    }

    return EXIT_SUCCESS;
}

테스트를 시작하기 전에 내가 가지고 있는 것:

/mnt # free
             total         used         free       shared      buffers
Mem:        125044        58540        66504            0          480
-/+ buffers:              58060        66984
Swap:            0            0            0

이제 테스트 코드를 실행하고 SD 카드에 10MB 파일을 생성하도록 요청합니다.

/mnt # mount /dev/sd_card2 /mnt/sd_card2
/mnt # ./random_size_file_generator 10 M /mnt/sd_card2

다른 창에서 나는 내 기억을 모니터링하기 시작했습니다

~ # free
             total         used         free       shared      buffers
Mem:        125044        60988        64056            0         2180
-/+ buffers:              58808        66236
Swap:            0            0            0
~ # free
             total         used         free       shared      buffers
Mem:        125044        65464        59580            0         2204
-/+ buffers:              63260        61784
Swap:            0            0            0

...

~ # free
             total         used         free       shared      buffers
Mem:        125044       123004         2040            0         1104
-/+ buffers:             121900         3144
Swap:            0            0            0

RAM은 2MB만 사용할 수 있습니다. 이제 코드를 중지하고 SD 카드를 마운트 해제하고 메모리 상태를 찾습니다.

/mnt # ./random_size_file_generator 10 /mnt/sd_card2
Created file /mnt/sd_card2/file_0
Created file /mnt/sd_card2/file_1
Created file /mnt/sd_card2/file_2
Created file /mnt/sd_card2/file_3
Created file /mnt/sd_card2/file_4
Created file /mnt/sd_card2/file_5
Created file /mnt/sd_card2/file_6
Created file /mnt/sd_card2/file_7
Created file /mnt/sd_card2/file_8
Created file /mnt/sd_card2/file_9
^C
/mnt # umount /mnt/sd_card2/
/mnt # free
             total         used         free       shared      buffers
Mem:        125044        58500        66544            0          472
-/+ buffers:              58028        67016
Swap:            0            0            0

그럼, 누군가 나에게 무슨 일이 일어나고 있는지 설명해 줄 수 있나요? 내 생각에 Linux는 모든 데이터가 SD 카드에 기록되도록 버퍼용 메모리 일부를 예약해 두었지만 프로그램이 중지되면 SD 카드가 마운트 해제될 때까지 메모리가 해제되지 않습니다.

미리 감사드립니다.

관련 정보