매치 시즈를 아이폰 웹에서 하시던 분이 판이 사라진다고 알려 주셨습니다. 화면 세 장이 같이 왔는데, 그 셋이 원인을 확정해 줬습니다.

제보읽은 것
메모리 46MB → 55MB 에서 멈춤 ("55mb에서 더 늘진 않았어요")누수가 아니다. 늘다 멈추는 건 정상이다
중단 1판 · 판 6실제로 한 번 죽었고, 게임이 그걸 세고 있었다
"설정창 켜놓고 가만히 있는데 재시작됐습니다 / 운전하느라 설정 대기중에"아무것도 안 하는 동안 죽었다

세 번째가 결정적이었습니다. 부하가 걸린 순간이 아니라 가만히 있을 때 죽었습니다. 그러면 누수도 GPU 부하도 아닙니다. iOS 사파리가 백그라운드로 밀린 탭을 그냥 버린 것입니다.

막을 수 없는 일입니다

브라우저가 메모리를 회수하려고 탭을 버리는 건 브라우저의 권한입니다. 게임이 "버리지 마세요"라고 말할 방법이 없습니다. 아무리 가볍게 만들어도, 다른 앱을 쓰다 돌아오면 버려져 있을 수 있습니다.

그래서 막는 대신 아프지 않게 만들기로 했습니다. 2초마다 판을 통째로 담아 둡니다 — 보드, 침식, 특수 블록, 점수, 판 번호, 남은 시간, 아이템까지. 돌아오면 거기서 이어서 합니다.

저장은 반드시 동기여야 합니다

여기서 저장 위치가 중요했습니다.

  • localStorage — 쓰는 순간 바로 기록됩니다. 탭이 그 직후에 죽어도 남습니다
  • 엔진이 기본으로 주는 저장소 — 브라우저에서는 IndexedDB 위에 올라갑니다. 비동기라 쓰기가 끝나기 전에 탭이 죽으면 그 판이 사라집니다

"탭이 죽는 것"에 대비하는 저장이 탭이 죽으면 같이 사라지면 아무 의미가 없습니다.

되살리기에 건 세 가지 제한

이어하기는 잘못 만들면 원래보다 나쁜 고장이 됩니다. 그래서 규칙을 셋 걸었습니다.

① 한 번 주고 지웁니다. 어떤 상태에서 반드시 죽는 판이라면, 되살릴 때마다 또 죽고 또 되살아납니다. 플레이어가 영영 빠져나오지 못합니다.

② 값이 하나라도 이상하면 통째로 버립니다. 반쯤 살아난 판은 이어서 하는 것이 아니라 새로운 고장입니다.

③ 30분이 지난 판도 버립니다. 어제 하던 판이 오늘 갑자기 살아나면 그건 이어하기가 아니라 놀라는 일입니다.

스스로 접은 판(일시정지 → 타이틀)과 정상적으로 끝난 판도 지웁니다.

"보드가 같다"가 거짓말이었습니다

배포하고 브라우저에서 새로고침해 봤더니 보드는 살아나는데 시간이 25초로 돌아가 있었습니다.

원인은 순서였습니다. 복구를 화면 구성 함수 끝에 넣었는데, 초기화 코드가 그 다음 줄에서 판을 새로 시작하는 함수를 부릅니다. 그게 보드를 새로 채우고 점수와 시간을 되돌렸습니다.

한참 헤맨 이유가 따로 있습니다. 확인할 때 "보드가 같은가"를 먼저 봤는데 그게 참으로 나왔습니다. 자유 플레이의 시작 보드는 결정적이라 — 같은 씨앗값으로 만들어지므로 — 복구가 통째로 지워져도 80칸이 똑같이 나옵니다. 맞는 답이 우연히 나오는 검사였던 셈입니다. 시간이 안 맞는 것을 보고서야 알았습니다.

복구를 판 시작 함수 뒤로 옮겼습니다. 새로고침 전 19.4초 → 후 19.4초, 보드 80칸 동일로 확인했습니다.

검사 123개가 전부 통과했습니다

이 결함이 살아 있는 동안 자동 검사는 123개 전부 통과였습니다. 검사는 저장 함수와 복구 함수를 직접 불러 보므로, 둘 다 정상으로 동작합니다. 문제는 그 둘 사이에 다른 함수가 끼어드는 순서였고, 그건 실제로 게임을 띄워 새로고침해 봐야 드러납니다.

그래서 이번에 검사를 112개에서 123개로 늘리면서 저장 → 불러오기 왕복을 넣었습니다. 거기서 끊기면 나머지 검사가 전부 소용없기 때문입니다. 다만 위 순서 문제는 여전히 사람이 새로고침해 봐야 잡힙니다 — 그 사실도 같이 적어 둡니다.

같이 손본 것

  • 일시정지 버튼을 따로 뒀습니다. 아이폰에는 뒤로가기 버튼이 없어서, 그 버튼에 기대면 설정과 다시하기로 들어갈 길이 없어집니다. 처음 넣은 버튼은 너무 작아 손가락 크기로 다시 키웠습니다
  • 움직이지 않는 화면은 초당 8번만 그립니다. 순위표·도움말·설정이 가만히 있으면서 60번씩 다시 그려지고 있었습니다. 그린 명령은 엔진이 붙들고 있으므로 다시 안 그려도 화면은 그대로입니다
  • 판 7·8에 새 이벤트를 넣었습니다. 판 6 이후로 새로 열리는 것이 없어서 잘하는 분일수록 아무 일도 안 일어나는 구간에 오래 머물렀습니다. 봇으로 재 보니 한 판이 16% 길어졌는데 여유 있는 시간의 비율은 77%에서 64%로 줄었습니다 — 길어지기만 하는 변경이 아니라는 뜻입니다

/siege/에서 바로 하실 수 있습니다. 탭을 닫았다 다시 열어 보시면 이어집니다.