부하가 심한 것도 아니었다. 메모리 스왑이 걸리면 알림을 받고, CPU가 놀고 있는지까지 지켜볼 만큼 서버처럼 쓰는 맥 관리에 공을 들여 왔다. 그래도 저절로 꺼졌다 켜지는 건 막지 못했다. 다행히 올여름 첫 사고 직후 사내 AI와 대화하며 만든 대책이 있어서, 이제는 컴퓨터가 갑자기 꺼져도 돌아가던 AI 작업 창 수십 개가 다시 살아난다. 그 방법은 따로 쓴다.
이 글은 왜 꺼졌는지에 대한 이야기다. 셸 스크립트(shell, 터미널에서 명령을 차례로 실행하는 작은 프로그램)를 여러 겹으로 자주 돌리는 맥을 몇 주씩 켜 두는 분이라면, 일반 메모리가 넉넉해도 같은 일이 생길 수 있다.
메모리가 남았는데 재부팅
9월 17일 아침 7시 11분, 맥 스튜디오가 저절로 꺼졌다 켜졌다. 5분쯤 뒤 서비스가 다시 돌아왔다.
10월 22일 낮 12시 17분에는 맥 미니 차례였다. 64GB 가운데 일반 메모리는 41.5GB만 쓰고 있었으니, 메모리가 모자란 게 아니었다.
재부팅 기록을 열어 보면 둘 다 같은 줄에서 멈춰 있다. 맥이 자기 살림용으로 따로 쓰는 커널 메모리 안에 1KB짜리 작은 칸들을 모아 두는 자리가 있는데(macOS 버전에 따라 이름만 조금 다르다), 그 자리가 20GB 가까이, 칸 수로 2천만 개 넘게 차 있었다. 이 자리가 꽉 차면 다른 메모리가 아무리 남아도 맥은 멈춘다.
같은 이유로 꺼진 게 확인된 것만 올해 세 번이다. 8월 16일 저녁 맥 스튜디오, 그리고 9월과 10월에 한 번씩.
시간표
| 시각 | 일어난 일 |
|---|---|
| 8월 16일 19:09 | 맥 스튜디오, 같은 칸이 차서 재부팅 |
| 8월 16일 이후 | 이 칸의 개수를 매시 적는 감시 시작(알림 문턱은 없음) |
| 9월 15일 06:24 | 맥 스튜디오에서 칸이 1초에 103개꼴로 늘기 시작 |
| 9월 17일 06:31 | 약 2,095만 개, 알림 0번 |
| 9월 17일 07:11 | 맥 스튜디오 재부팅(약 2,124만 개, 20GB) |
| 10월 18일 23시 | 맥 미니에서 같은 칸이 한 시간에 20만~35만 개씩 늘기 시작 |
| 10월 21일 13:58 | 맥 미니 첫 경보, 그 뒤 6시간마다 한 번씩 |
| 10월 22일 07:58 | 네 번째 경보, 아무 반응 없음 |
| 10월 22일 12:17 | 맥 미니 재부팅(약 2천만 개) |
9월 맥 스튜디오는 낮과 밤에 늘어나는 속도가 같았다. 사람이 일하는 양을 따라가는 게 아니라, 기계가 정해진 간격으로 계속 돌리는 무언가가 범인이라는 단서였다. 우리는 AI 작업 창을 여러 개 몇 주씩 켜 두는데, 창마다 몇 초에 한 번씩 도는 작은 셸 스크립트(상태 표시 같은 것)가 붙어 있다.
셸이 셸을 부를 때 1KB
원인은 외부 연구 글이 먼저 공개한 macOS 결함이었다(Photon, "We found a kernel memory leak in macOS that any shell script can trigger"). `#!`로 시작하는 스크립트가 또 다른 `#!` 스크립트를 실행하면, 커널이 1KB 칸을 하나 쓰고 재부팅 전까지 돌려주지 않는다.
우리 맥에서도 그대로 되는지 같은 일을 3,000번씩 돌려 봤다.
| 실행 방식 | 3,000번 뒤 늘어난 칸 |
|---|---|
| 스크립트 하나만 | 거의 0 |
| 스크립트가 스크립트를 부름(2단) | 약 3,000개 |
| 3단 | 약 6,000개 |
| 4단 | 약 9,000개 |
자료: 맥 스튜디오 재현 시험, 단마다 3,000번 실행
한 번 겹칠 때마다 정확히 1KB였다. 스크립트 하나만 돌릴 땐 새지 않고, 겹칠 때만 샌다.
10월 맥 미니도 같은 시험에서 3,000번에 약 3,150개가 늘었다. 다만 10월 18일 밤부터 하루 4.5~7GB씩 쌓인 그 많은 양이 정확히 어느 프로그램에서 나왔는지는 끝내 짚지 못했다. 같은 칸이 같은 모양으로 늘었으니 같은 결함으로 보고 있다(추정).
울렸는데 아무도 못 본 경보
9월에는 경보가 아예 없었다. 8월 사고 뒤에 이 칸의 개수를 매시 적어 두기 시작했지만, 값을 적기만 하고 넘치기 전에 알려 주는 문턱이 없었다. 꺼지기 40분 전에도 기록은 2,095만 개를 가리키고 있었다.
10월은 더 아깝다. 그사이 문턱을 달아 둔 덕에 맥 미니는 꺼지기 22시간 전부터 경고가 네 번 울렸다. 경고는 사람이 결정을 모아 보는 대화방으로 갔고, 다른 알림 사이에 묻혀 답글 하나 달리지 않았다. 계획해서 재부팅할 시간은 충분했는데, 그 시간을 아무도 쓰지 않았다.
새는 길 줄이기와 새 경보
애플 결함이라 결함 자체를 우리 코드로 고칠 수는 없다. 대신 새는 길을 줄였다. 매일 새벽 도는 작업 하나를 스크립트끼리 부르지 않고 실행기를 직접 부르게 바꿨다.
| 항목 | 전 | 뒤 |
|---|---|---|
| 같은 시험에서 늘어난 칸 | 4,850개 | 229개 (−95%) |
자료: 맥 미니에서 바꾸기 전후로 같은 새벽 작업 시험
함정도 하나 있었다. 위쪽 어딘가에 `#!` 스크립트가 하나라도 끼어 있으면, 그 아래에서 실행기를 직접 불러도 그대로 샌다. 맨 위부터 겹치는 곳을 없애야 줄어든다.
경보도 두 가지를 바꿨다.
- '얼마나 찼나'보다 '이 속도면 언제 차나'를 본다. 최근 6시간 속도로 꽉 차는 시각을 계산해 함께 보낸다.
- 경고를 사람 대화방에만 두지 않고, 바로 움직일 수 있는 AI 작업 창에도 같이 보낸다.
3GB가 차 있어도 거의 안 늘면 괜찮고, 1GB라도 빨리 늘면 위험하다. 이 방식으로 다시 보니 꺼진 두 대 말고 맥북 프로도 그 속도대로면 130일쯤 뒤에 꽉 찰 참이었다.
한계와 남은 것
- 결함은 그대로다. 우리가 줄인 건 새벽 작업 한 곳이고, 다른 곳에서 스크립트가 겹쳐 돌면 여전히 샌다. 새는 양이 0이 되는 건 애플이 고친 뒤다.
- 10월 맥 미니의 많은 양이 어느 프로그램에서 나왔는지는 못 짚었다. 같은 결함이라는 건 추정이다.
- 새 경보도 결국 누군가 움직여야 쓸모가 있다. 경보를 보고 재부팅 시각을 잡는 일은 아직 사람 몫으로 남겨 두었다.
- 이 칸이 다시 차는 길은 하나가 아니었다. 11월에는 업데이트 뒤에 또 늘었다(2탄).
배운 것
- 일반 메모리가 남아도 커널의 1KB 칸 하나가 차면 맥은 멈춘다. `sudo zprint`로 kalloc.1024가 들어간 줄을 가끔 보자.
- 경보는 '얼마나 찼나' 대신 '이 속도면 언제 차나'로 건다.
- 시간이 걸린 장비 경보는 사람 대화방 한 곳에만 보내지 않는다.