버퍼
버퍼는 데이터를 주고받는 두 쪽 사이에 두는 임시 저장 공간입니다. 한쪽이 데이터를 만들어 내는 속도와 다른 쪽이 그것을 가져가는 속도가 다를 때, 그 차이를 메워 두 쪽이 서로 기다리지 않게 해 줍니다. 데이터는 버퍼에 잠깐 머물렀다가 받는 쪽이 준비되면 빠져나갑니다.
쉽고 빠른 이해
버퍼는 데이터를 주고받는 두 쪽 사이에서 데이터를 잠깐 맡아 두는 저장 공간입니다. 프로그램이 파일에 한 글자씩 쓸 때마다 디스크에 바로 적지 않고, 몇천 바이트가 모일 때까지 버퍼에 쌓아 두었다가 한꺼번에 씁니다.
이게 없으면 느린 쪽 속도에 빠른 쪽이 그대로 맞춰야 합니다. 글자 하나 쓸 때마다 디스크가 준비될 때까지 기다리면 프로그램 전체가 느려집니다.
어떻게 도나:
- 빠른 쪽이 데이터를 버퍼에 채웁니다
- 버퍼가 다 차거나 정해진 때가 되면 느린 쪽에 한꺼번에 넘깁니다
- 느린 쪽이 가져가면 버퍼는 다시 빈 상태로 돌아갑니다
대가는 메모리와 지연입니다. 버퍼는 그만큼 공간을 차지하고, 데이터는 버퍼에 머무는 동안 상대에게 곧바로 전해지지 않습니다. 그래서 응답을 바로 돌려줘야 하는 실시간 통화·게임 같은 곳에서는 버퍼를 얇게 두거나 아예 건너뜁니다.
상세
우체통을 생각해 봅니다. 편지를 넣는 사람과 편지를 걷어 가는 집배원은 서로 다른 때에 움직입니다. 우체통이 없다면 편지를 넣는 사람은 집배원이 올 때까지 편지를 손에 들고 서 있어야 합니다. 버퍼는 컴퓨터 안에서 이 우체통과 같은 일을 합니다.
이 절은 먼저 속도가 다른 생산자와 소비자를 버퍼가 어떻게 잇는지를 보고, 버퍼가 시간에 따라 채워지고 비는 순서를 봅니다. 그다음 자주 헷갈리는 큐와 무엇이 다른지를 가르고, 버퍼가 다 찼을 때 벌어지는 두 갈래와 오히려 버퍼를 줄이거나 안 쓰는 경우를 봅니다. 마지막으로 버퍼가 메모리 위에 있다는 사실이 무엇을 뜻하는지와, 일상에서 마주치는 버퍼링을 봅니다.
속도가 다른 두 쪽을 잇는다
데이터를 만들어 내는 쪽을 생산자라 부르고, 그것을 가져다 쓰는 쪽을 소비자라 부릅니다. 이 둘이 얽히는 상황을 다루는 갈래를 생산자-소비자 문제라고 합니다. 버퍼는 이 둘 사이에 놓여 서로의 속도를 몰라도 되게 해 줍니다.
생산자는 데이터를 만들 때마다 버퍼에 넣고 돌아갑니다. 소비자가 지금 바쁜지 한가한지는 신경 쓰지 않습니다. 소비자도 마찬가지로 자기 사정에 맞춰 버퍼에서 꺼내 갑니다. 둘 다 상대가 지금 무엇을 하는지 몰라도 자기 일을 계속할 수 있습니다.
버퍼가 차고 비는 순서
버퍼는 시간이 지나며 아래 네 상태를 오갑니다.
stateDiagram-v2
[*] --> 비어있음
비어있음 --> 채워지는중: 생산자가 넣는다
채워지는중 --> 가득참: 자리가 다 찬다
채워지는중 --> 비워지는중: 소비자가 꺼내간다
가득참 --> 비워지는중: 소비자가 꺼내간다
비워지는중 --> 비어있음: 다 꺼내간다
생산자와 소비자는 대개 동시에 움직입니다. 생산자가 넣는 동안 소비자도 그만큼 꺼내 가면 버퍼는 다 차거나 완전히 비는 순간보다 채워지는 중과 비워지는 중 사이를 오가는 시간이 훨씬 깁니다.
버퍼와 큐는 무엇이 다른가
버퍼와 큐는 자주 같이 쓰여 헷갈립니다. 버퍼는 데이터를 잠깐 맡아 두는 저장 공간 자체를 가리키고, 큐는 그 안에서 무엇을 먼저 꺼낼지 정하는 순서 규칙을 가리킵니다.
먼저 들어온 데이터를 먼저 꺼내는 규칙을 FIFO(First-In-First-Out, 선입선출)라고 부릅니다. 대부분의 버퍼는 이 FIFO 규칙으로 관리됩니다.
다만 반드시 그래야 하는 것은 아닙니다. 자리가 다 차면 가장 오래된 데이터를 지우고 새 데이터로 덮어쓰는 순환 버퍼도 있습니다.
버퍼가 다 찼을 때의 두 갈래
버퍼에 빈 곳이 없는데 생산자가 계속 넣으려고 하면 갈 길은 둘로 나뉩니다.
하나는 생산자에게 신호를 보내 잠깐 멈추게 하는 것입니다. 생산자가 이 신호를 받고 속도를 늦추는 방식을 백프레셔라고 부릅니다. 다른 하나는 신호 없이 밀어붙이는 것입니다. 오래된 데이터를 지우고 새 데이터로 덮어쓰거나, 정해진 크기를 넘겨 버퍼 밖의 메모리까지 건드리기도 합니다. 뒤의 경우를 버퍼 오버플로라고 부르고, 프로그램을 멈추게 하거나 보안 사고로 이어지는 심각한 문제입니다.
버퍼를 줄이거나 안 쓰는 경우
버퍼는 지연을 대가로 처리량과 안정성을 얻습니다. 그래서 응답을 최대한 빨리 돌려줘야 하는 곳에서는 버퍼를 얇게 두거나 아예 건너뜁니다. 실시간 음성 통화나 온라인 게임처럼 지연이 곧 품질로 이어지는 경우가 그렇습니다.
이런 자리에서는 버퍼에 데이터를 조금만 모으고 바로 내보냅니다. 늦게 도착한 데이터는 기다리지 않고 버리기도 합니다. 데이터를 하나도 빠뜨리지 않는 것보다 지금 이 순간의 반응이 더 값지기 때문입니다.
버퍼는 사라질 수 있다
버퍼는 대개 메모리 위에 놓입니다. 메모리는 전원이 꺼지면 담긴 내용이 사라지는 성질을 갖습니다. 그래서 버퍼에 있는 동안 정전이 나거나 프로그램이 강제로 종료되면, 아직 소비자에게 넘어가지 못한 데이터는 그대로 사라집니다.
디스크에 남겨야 하는 데이터라면 버퍼에만 두지 않고 별도로 기록해 둡니다. 버퍼를 강제로 비워 상대에게 곧장 넘기는 동작을 플러시라고 부릅니다.
일상에서 마주치는 버퍼링
영상을 보다가 화면이 멈추고 동그란 표시가 도는 것을 흔히 버퍼링이라고 부릅니다. 원리는 같습니다. 재생 프로그램은 화면에 보여 주기 전에 영상 데이터를 버퍼에 미리 받아 둡니다.
버퍼에 데이터가 충분히 쌓이면 재생을 시작하거나 이어 갑니다. 네트워크가 느려 데이터가 버퍼를 채우는 속도보다 재생 속도가 빨라지면 버퍼가 비어 재생이 멈춥니다. 화면의 그 표시는 버퍼가 다시 채워지기를 기다린다는 뜻입니다.
관련 항목
메모리 위에서 버퍼와 이웃하는 개념
버퍼로 속도차를 다루는 개념
버퍼가 다 찼을 때 생기는 문제
디스크와 네트워크에서 버퍼를 쓰는 방식
논블로킹 입출력 · 디스크립터 · 파일 디스크립터 · 네트워크
버퍼를 여러 장 겹쳐 쓰는 기법
더블 버퍼링 · 순환 버퍼 · 프레임버퍼
다른 이름: buffer