선 하나 옮길 때마다 283MB — 12번째 편집에 화면이 죽었다

문제 해결··7분 읽기·

오늘 배울 것 되돌리기 기록을 문서 전체로 만들면, 문서가 커질 때 그 기록이 메모리를 다 먹습니다.

이 글은 이렇게 만들었습니다AI 활용 원칙

  • 나 어느 문제를 먼저 파볼지 정했어요. 큰 도면 쪽을 먼저 보기로 골랐고, 그다음 작업도 같은 쪽으로 정했습니다.

  • AI 측정과 설계를 맡고 코드를 썼습니다. 교차검증에서 "검사가 보는 범위가 좁다", "얼림 모드가 정말 켜졌는지 확인하지 않는다"가 나왔어요.

결과부터 — 편집 한 번의 값이 283MB에서 3.3MB가 됐어요

저는 AI와 함께 설치해서 쓰는 무료 2D 도면 프로그램을 만들고 있어요.

객체가 약 85만 개인 큰 도면을 열고, 선을 하나씩 옮겨 봤습니다.

편집을 한 번 할 때마다 메모리가 283MB씩 늘었어요. 그때마다 화면이 6~17초 멈췄습니다.

11번째 편집 뒤에는 3,766MB까지 찼어요. 화면이 쓸 수 있는 메모리 상한은 4,192MB입니다. 12번째 편집에서 화면이 끝났어요.

원인은 되돌리기였습니다. 기록을 만들 때 도면 전체를 통째로 베끼고 있었어요.

기록 방식을 "바뀐 것만 베끼기"로 바꿨습니다. 결과는 이렇게 달라졌어요.

재는 것

고치기 전

고친 뒤

편집 한 번당 메모리

+283MB

+3.3MB

되돌리기 기록 한 번 만들기

도면 전체 베끼기

15ms

표의 ms는 밀리초, 1초를 1,000으로 나눈 시간이에요.

되돌리기는 100번까지 거슬러 갈 수 있는데, 다 채워도 기록이 차지하는 양은 약 330MB입니다.

설치해서 쓰는 프로그램에서도 선을 15번 옮겨 봤어요. 15번 내내 편집당 3.3MB였습니다.

왼쪽에는 도면 전체를 찍은 사진이 천장까지 쌓여 있고, 오른쪽에는 바뀐 선 하나만 적은 작은 쪽지 한 장이 놓여 있다
AI로 생성한 설명용 이미지입니다. 실제 화면이 아닙니다.

무엇이 문제였나 — 되돌리기가 편집마다 도면을 통째로 베꼈어요

되돌리기는 Ctrl+Z 입니다. 취소를 하려면 직전 상태를 어딘가에 남겨 둬야 해요.

그래서 제 프로그램은 편집 전에 도면을 사진처럼 찍어 뒀습니다.

문제는 그 사진이 도면 전체였다는 점이에요. 선 하나를 옮기는데 객체 약 85만 개를 모두 새로 베꼈습니다.

도면 안의 블록 정의도 같이 베꼈어요. 이 도면에는 블록 정의가 731개, 그 안의 객체가 101,890개 있었습니다.

되돌리기 상한은 100단계예요. 그 큰 사진을 100장까지 쌓아 둔다는 뜻입니다.

이 결함은 큰 도면을 시험하다 드러났어요. 그전까지는 "큰 도면의 화면 메모리 한계"로만 알고 있었습니다.

그런데 메모리가 모자란 게 아니었어요. 편집 한 번이 도면 크기만큼의 메모리를 계속 붙잡고 있었던 겁니다.

왜 몰랐나 — 측정이 먼저 거짓말을 했어요

처음에는 설치한 프로그램에서 메모리를 재려 했어요. 그런데 화면이 바쁘면 메모리를 재는 값이 빈 채로 돌아왔습니다. 가장 많이 쓴 순간을 놓친 거예요.

그래서 도면을 열고 저장하는 같은 코드를 시험용 브라우저에서 돌려 다시 쟀습니다. 그제서야 편집마다 283MB가 보였어요.

고친 다음에는 반대로 어긋났습니다. 설치한 프로그램에서는 편집당 8.4MB가 나왔어요. 브라우저에서 잰 3.3MB와 맞지 않았습니다.

편집마다 진단을 따로 남기고 다시 쟀어요. 범인은 자동 저장이었습니다. 기본 간격이 10분인데, 그 자동 저장이 9~15번째 편집과 겹쳤어요.

자동 저장을 끄고 다시 쟀습니다. 선을 15번 옮기는 동안 내내 편집당 3.3MB였어요.

그래서 8.4MB는 틀린 값입니다. 고칠 곳은 코드가 아니라 재는 조건이었어요.

어떻게 풀었나 — 바뀐 것만 베끼고, 빠뜨린 곳은 일부러 얼려서 찾았어요

  1. 되돌리기 기록은 목록만 듭니다. 사진 대신 "그때 거기 있던 객체들"을 가리키는 목록만 만들어요. 도면 전체를 베끼는 것과는 비교가 안 될 만큼 작습니다.

  2. 객체를 바꿀 때는 그 하나만 복제합니다. 목록이 가리키고 있는 객체는 손대면 안 돼요. 그래서 바꾸기 직전에 그 객체 하나만 베껴 같은 자리에 끼우고, 베낀 쪽을 바꿉니다. 코드로는 이만큼이에요.

own(id) {
  const e = this.entities.get(id);
  if (this.owned.has(e)) return e;   // 이미 내 것 → 그대로 바꾼다
  const c = cloneEntity(e);          // 기록과 공유 중 → 이 하나만 베낀다
  this.entities.set(id, c);          // 같은 자리에 바꿔 끼운다
  this.owned.add(c);                 // 이제 내 것이라고 표시한다
  return c;
}
  1. 빠뜨린 곳은 일부러 얼려서 찾았어요. 2번을 거치지 않고 객체를 바로 고치는 자리가 코드에 남아 있었습니다. 그래서 시험할 때만 공유된 객체를 "얼리는" 모드를 만들었어요. 얼린 객체에 손을 대면 그 자리에서 오류가 납니다.

  2. 그 모드로 시험 222개를 전부 돌렸습니다. 80개가 실패하면서, 손대면 안 되는 객체를 건드린 자리 66군데가 드러났어요. 고친 뒤에는 전부 통과하고 그런 자리는 0건이었습니다.

  3. 얼림이 정말 켜졌는지 대조합니다. 교차검증에서 나온 지적이에요. 얼림 모드라고 하고 실제로는 평소 모드였다면, 시험은 조용히 전부 통과하거든요. 그래서 켜졌는지 확인하는 스크립트를 붙였습니다.

  4. 검사가 진짜 잡는지 확인합니다. 결함 11종을 일부러 코드에 심어 봤어요. 11종 모두 검사에 걸렸습니다. 이렇게 보이면 성공이에요.

공유된 도면 위에 투명한 유리 덮개가 씌워져 있고, 손이 닿은 자리에 금이 가며 붉은 표시가 떠오른다
AI로 생성한 설명용 이미지입니다. 실제 화면이 아닙니다.

자기 것에 대 볼 질문은 하나예요. 내 되돌리기 기록은 문서 전체인가요, 바뀐 것만인가요?

되돌리기는 매번 전체를 사진 찍는 게 아니라, 바뀐 것만 베껴 두는 것입니다. 그리고 숫자가 서로 안 맞을 때는 코드보다 재는 조건을 먼저 의심해야 합니다.

용어 풀이

  • 되돌리기(Ctrl+Z) 방금 한 일을 취소하는 기능이에요. 정확히는 편집 직전 상태를 남겨 두고 그리로 돌려주는 장치입니다.

  • 메모리 컴퓨터가 지금 하는 일을 펼쳐 두는 책상이에요. 정확히는 프로그램이 돌아가는 동안 값을 담아 두는 공간입니다. MB(메가바이트)는 그 크기를 재는 단위예요. 파일을 넣어 두는 저장 공간과는 다릅니다.

  • 메모리 상한 책상 넓이의 한계예요. 정확히는 그 프로그램이 쓸 수 있는 메모리 최대치입니다. 넘으면 프로그램이 끝나요.

  • 복사-후-쓰기 여럿이 같은 문서를 돌려 보다가 고칠 사람만 자기 몫을 복사하는 방식이에요. 정확히는 공유 중인 값을 바꿀 때 그 값 하나만 복제합니다. 위 2번 단계가 바로 이 방식의 이름이에요.

  • 자동 저장 틈틈이 알아서 저장해 주는 기능이에요. 정확히는 정해진 시간마다 지금 상태를 파일로 써 두는 장치입니다. 제 프로그램은 기본 10분입니다.

공유

댓글

0/2000

아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요.