diff options
Diffstat (limited to 'docs/design')
| -rw-r--r-- | docs/design/013-memory-budget.md | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/docs/design/013-memory-budget.md b/docs/design/013-memory-budget.md index fe8736a..97bd8a6 100644 --- a/docs/design/013-memory-budget.md +++ b/docs/design/013-memory-budget.md @@ -1,10 +1,10 @@ # 013 — 앱 전체 메모리 예산 -작성일: 2026-09-30. 상태: 1단계 구현. +작성일: 2026-09-30. 상태: 세 단계 모두 했다(3단계는 측정). [외부 리뷰 004](../outside-feedback/feedback-004.md)의 둘째 권고에서 시작한다. 측정은 [104](../research/104-where-memory-goes.md)에 있다. -지금의 `--budget`은 요청 payload의 접수만 묶는다. 앱의 목록, outbox, 붙들린 스냅숏, 전송의 사본은 아무것도 묶지 않는다. 작은 -기기에서 오래 도는 노드라면 무엇이 얼마나 쓰는지 정해져 있어야 하고, 넘칠 때 무엇을 하는지도 정해져 있어야 한다. +이 설계 전에는 `--budget`이 요청 payload의 접수만 묶었다. 앱의 목록, outbox, 붙들린 스냅숏, 전송의 사본은 아무것도 묶지 +않았다. 작은 기기에서 오래 도는 노드라면 무엇이 얼마나 쓰는지 정해져 있어야 하고, 넘칠 때 무엇을 하는지도 정해져 있어야 한다. ## 결정 @@ -56,15 +56,19 @@ | 무엇 | 상한 | 이유 | |---|---|---| | 붙들린 스냅숏 | 붙든 판마다 상태 한 벌. 붙드는 쪽(연결 스레드, 표면, 체크포인트)이 H이면 최악 (1 + H) × 예산 | 104에서 고쳤다. 전에는 한이 없었다 | -| 전송의 사본 | 링크 ring과 HTTP 큐가 outbox를 한 번 더 든다(한 건에 0.8배, 1.4배) | 2단계에서 창으로 묶는다 | +| 전송의 사본 | 보내는 곳(`--send`)마다 창 하나: 받는 쪽이 가진 것 너머로 `--window` 바이트(4 MiB)와 65,536건 | 2단계. 전에는 outbox를 한 번 더 들었다(한 건에 0.8배, 1.4배) | | 요청 payload | `--budget` | 지금의 접수 예산 | -| 체크포인트 | 이미지를 쓰는 동안 스냅숏 하나 | 붙들린 스냅숏의 한 경우 | +| 체크포인트 | 이미지를 쓰는 동안 스냅숏 하나. 그동안 고친 잎과 바꾼 텍스트만 더 든다 | 붙들린 스냅숏의 한 경우. SD 카드에서 22.4 MB 목록을 8초쯤 쓰는 동안 +3.0–4.4 MiB였다(104) | ## 단계 1. 상태 바이트를 세고, `--memory`로 예산을 두고, 넘칠 때 사건을 거절한다. 전달의 거절은 들은 번호로 세지 않는다. 2. 전송의 창: 링크와 HTTP 전달이 outbox 전체가 아니라 창만큼만 받는다. 전달되면 다음을 받는다. -3. 체크포인트가 쓰는 동안의 메모리를 잰다. + - 소유자가 보내는 곳마다 outbox에서의 자리를 기억해, 새로 넣을 것만 본다. outbox에서 나간 보내기의 수(`sends_gone`)만큼 + 자리를 뒤로 물리므로, 앞의 것이 지워져도 건너뛰는 것이 없다. 저장 뒤와 전달 뒤에 창을 채운다. + - 창이 차도 하나는 넣는다. 창보다 큰 보내기 하나도 간다. +3. 체크포인트가 쓰는 동안의 메모리를 잰다. 잰 값은 104에 있다. 쓰는 동안 고친 것만큼 는다. 예산이 세는 상태의 2배(상태 + 한 벌과 스냅숏 한 벌)를 넘지 않고, 잰 최고는 상태 바이트의 약 2배(상주)였다. ## 검사 @@ -84,7 +88,13 @@ 기다리던 주문이 모두 한 번씩 들어온다. 가득 찬 2초 동안 거절은 7번이다(기다림이 없으면 27,809번). - check.py `server_answers_memory`: 답이 보내기보다 큰 영수증을 남긴다. 영수증이 예산을 채우면 답이 기다리고 주문이 503 `memory`를 받는다. 비우면 기다리던 답이 모두 한 번씩 적용되고, API는 주문마다 한 번씩만 불렸다. +- check.py `server_windows`: 출력 둘(링크 하나, HTTP 하나)의 받는 쪽이 모두 꺼진 채 300건을 보낸다. 창(2,000 B)이 찬다. + 받는 쪽이 뜨면 둘 다 300건을 한 번씩 받는다. 전달 뒤에 창을 채우지 않으면 117건에서 멈춘다. - 021의 run.py `budget`: 상태 4 MB가 4초 남짓에 차고, 상주 메모리가 9.6–9.8 MiB에 멈춘다(예산 없이 30초에 45.9 MiB). +- 021의 run.py `link-down`, `wire-down`(창 4 MiB): 창이 찬 뒤로는 보낸 것 한 건에 상주 219 B, 218 B로 outbox만큼만 는다(30초 + 전체로 전에는 399 B, 534 B). +- 021의 run.py `unheld --items 200000 --stores`(SD 카드): 체크포인트 두 번이 각각 +3.0 MiB, +4.4 MiB를 남겼다. 최고 상주 + 42.6 MiB는 상태 22.4 MB의 약 2배다. ## 중단 기준 |
