MIGNON BLOG

So Long 프로젝트: 메모리 누수 문제 해결 방안

목차

So Long 프로젝트: 메모리 누수 문제 해결 방안

안녕하세요, 이번 포스트에서는 42Mulhouse의 과제 중 하나인 So Long 프로젝트에 대해 이야기하고자 합니다. 특히 Sprite 애니메이션과 메모리 누수 문제에 대한 해결 방안을 다룰 예정입니다. Codam의 MLX42 라이브러리를 사용하여 구현한 경험을 공유합니다.

Sprite 애니메이션 구현

Sprite 애니메이션은 방향키를 누르지 않아도 자동으로 움직이는 애니메이션을 의미합니다. 실제로 이를 구현한 사람들은 time과 같은 함수를 사용했다고 합니다. 저는 아직 이를 구현해보지 못했지만, 향후 다른 프로젝트를 통해 시도해보고자 합니다.

메모리 누수 문제 해결

So Long 프로젝트를 진행하면서 많은 메모리 누수 문제를 겪었습니다. 기본적으로 맵 배열 뿐만 아니라 MLX42로 불러온 이미지도 메모리 해제를 해주어야 합니다. 다음은 제가 사용한 코드입니다.


static void ft_free_imgs(t_map *map)
{
    if (map->gr)
        mlx_delete_image(map->mlx, map->gr);
    ...
    return ;
}

// check는 이미지 할당 필요 여부를 확인하는 플래그입니다.
void ft_tout_free(t_map *map, int check)
{
    if (map->map != NULL)
    {
        ft_free_arr(map->map);
        map->map = NULL;
    }

    if (map->mapf != NULL)
    {
        ft_free_arr(map->mapf);
        map->mapf = NULL;
    }

    if (check == 1)
    {
        ft_free_imgs(map);
        map = NULL;
    }

    return ;
}

MLX42 함수를 사용하여 메모리 할당을 해제해 주었지만, 프로그램 창을 닫을 때 메모리 누수가 발생했습니다. 이는 메인 함수 종료 시 배열과 이미지 메모리를 해제하기 전에 이미지 메모리를 해제하는 mlx 포인터를 먼저 해제했기 때문입니다.

ft_tout_free(&map, 1);
mlx_terminate(map.mlx); // 이 줄이 ft_tout_free() 위에 있었습니다.
get_next_line(0, CLEAR);

get_next_line 함수의 메모리 누수 문제

마지막까지 문제를 일으켰던 것은 get_next_line 함수에서 할당된 static 변수였습니다. 이번 프로젝트에서는 함수 호출 시 플래그를 설정하여 마지막에 메모리를 해제하는 방법으로 해결했지만, 더 간단하게 해결할 수 있는 방법도 있습니다. 배열 크기를 버퍼 사이즈로 정해서 선언하면 메모리 할당과 해제의 필요성이 없어집니다.

char *clear_gnl(char *backup[1024])
{
    int cursor;
    cursor = 0;
    while (cursor < 1024)
        free(backup[cursor++]);
    return (NULL);
}

// 현재는 mode 변수를 통해 할당 해제를 처리했습니다.
// static char *backup[1024]를 static char backup[BUFFER_SIZE + 1][1024]로 바꾸면 해결될 수 있습니다.
char *get_next_line(int fd, int mode)
{
    static char *backup[1024];
    char *oneline;

    if (mode == CLEAR)
        return (clear_gnl(backup));

    if (fd < 0 || BUFFER_SIZE <= 0 || read(fd, 0, 0) < 0)
        return (NULL);

    backup[fd] = get_read(fd, backup[fd]);
    if (!backup[fd])
        return (NULL);

    oneline = get_one(backup[fd]);
    if (!oneline)
        return (NULL);

    backup[fd] = set_next(backup[fd]);
    if (backup[fd] == (char *)8)
    {
        backup[fd] = NULL;
        free(oneline);
        return (NULL);
    }

    return (oneline);
}

이번 프로젝트에서는 전체 코드를 수정하기에는 힘든 상태였기 때문에 위와 같은 임시 방편을 사용했습니다. 곧 제대로 수정할 예정입니다.

문자열 출력 함수

보너스 과제에서 화면에 문자열을 출력하기 위해 다음과 같은 함수를 사용했습니다. 글씨가 뭉개지지 않도록 해당 부분의 이미지만 반복적으로 재출력해 주었습니다.

mlx_put_string(map->mlx, count, 12, 15);
// mlx_put_string(mlx 포인터, 출력할 문자열, 위치, 위치);

Codam의 MLX42 사용이 공식적으로 허가되어 Codam의 MLX42를 사용하였습니다.

혹시라도 질문 사항이 있으시면 편하게 댓글 남겨주세요. 아는 내용이라면 최대한 도와드리겠습니다!

감사합니다.

관련글