1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
# 049 — 앱이 쉴 때 작업 슬롯도 비운다
Pure 실행 영역은 호출자가 제공한 작업 슬롯을 보유한다. 기존 네이티브 작성 앱은
입력 한 건에는 슬롯 하나, 저장·복원의 `READ → WRITE` 전달에는 둘이 필요해서
**모든 유휴 인스턴스에 `PureWork[2]` 448 B를 계속 예약**했다. 이전에 계산 정의를
공유해 scalar 인스턴스를 280 B까지 줄인 [028](028-shared-fixed-program.md) 이후에는
이 448 B가 독립 앱의 반복 비용에서 더 큰 부분이었다.
코어에 `pure_runtime_bind()`를 추가했다. 영역은 작업 슬롯 없이 시작할 수 있고,
호스트가 진행 중인 호출에 필요한 슬롯을 제공한다. 네이티브 앱은 입력에 1개,
저장·복원에 2개를 **소유 스레드의 호출 스택에만** 두고, 결과·대여가 모두 회수된
뒤 분리한다. 슬롯을 바꿔도 영역의 예산·누적 계수·티켓 세대는 유지된다. 진행 중
작업, 완료를 보유한 티켓, 다른 영역이 고정한 본문이 있으면 분리를 거절한다.
[코어의 실제 대여·세대 검사](../../prototypes/connections/test-runtime.c)는 수신 영역이
원본 본문을 소비할 때까지 분리가 실패하고, 회수 뒤 성공하며, 오래된 티켓이 새
슬롯을 가리키지 못함을 확인한다. 선택형 장시간 비동기 HTTP 호스트는 계속 고정
슬롯을 사용한다. 이 변경은 동기 앱의 호출 수명에만 적용한다.
[전체 앱 메모리 A/B 원자료](../../prototypes/workbench/results/2026-09-24-idle-work-binding/app-memory.json)는
같은 준비된 `routed-layout.pure`와 같은 scalar 아카이브로 각각 **독립 앱
1,000개**를 초기화한다. 각 앱이 코어를 통해 입력을 처리하고 서로 다른 문서를
저장하며, 다섯 앱을 다시 복원한다. 실행마다 접수와 회수가 3,010건씩 일치하고
저장 파일을 확인한다. 이전 앱 소스는 [동결된 작성 호스트
소스](../../prototypes/workbench/results/2026-09-24-native-desktop/sources/native/app.c)와
[헤더](../../prototypes/workbench/results/2026-09-24-native-desktop/sources/native/app.h)를
그대로 사용했다. 비교 하네스는 현재 소스에서 두 실행물을 다시 빌드한다.
Linux에서 Zig 0.15.2가 있다면 저장소 루트에서
`python3 prototypes/workbench/manage.py native prototypes/workbench/examples/routed-layout.pure`
후 `(cd prototypes/workbench && python3 native/check_app_memory.py)`로 재현한다.
| Linux AArch64 / GCC 14, 같은 실제 앱 1,000개 | 이전 고정 슬롯 | 호출 중 대여 |
|---|---:|---:|
| 앱 컨트롤러 / 인스턴스 | 928 B | 480 B |
| scalar 상태 / 인스턴스 | 280 B | 280 B |
| 초기화 후 RSS 증가, 3회 중앙값 | 1,264 KiB | 832 KiB |
| 저장 후 RSS 증가, 3회 중앙값 | 1,328 KiB | 896 KiB |
| A/B 하네스 실행물 `text` | 35,698 B | 35,962 B |
컨트롤러에서는 인스턴스당 448 B, 실제 프로세스 RSS 증가량에서는 이 작업의
**432 KiB**가 줄었다. A/B 둘 다 변경 후의 같은 코어를 링크했고, 앱 호스트만
다른 실행물의 `text` 차이는 264 B다. 공통 코어의
[최신 크기 검사](../../prototypes/connections/results/2026-09-24-idle-work-binding/core.json)는
`text` 5,932→6,076 B, 영역 200 B, 작업 슬롯 224 B다. 코어의 기존
6,144 B 상한은 올리지 않았다. 코드 증분을 숨기지 않으면서 유휴 앱 1,000개의
반복 예약을 줄인 결과다.
메모리가 사라진 것은 아니다. [GCC 정적 스택 추정](../../prototypes/workbench/results/2026-09-24-idle-work-binding/stack-baseline.su)을
[새 실행](../../prototypes/workbench/results/2026-09-24-idle-work-binding/stack-elastic.su)과
비교하면 `pure_native_app_action`은 208→432 B, 저장·복원 공통 `transfer`는
288→736 B다. 각각 224 B와 448 B를 **호출 중에** 스택으로 옮겼다. 이 수치는
함수 자신의 정적 스택 추정이며 호출 체인 전체의 피크가 아니다. 한 소유 스레드가
동기 호출을 진행하는 현재 앱 계약에 맞는 선택이고, 작업을 반환 뒤에도 보유하는
호스트에는 이 배치를 적용하지 않는다.
## 선택한 배포 묶음의 비용
변경 후 기존 `--strip-debug` 방식의 CLI+TUI 압축 묶음은
[35,847 B](../../prototypes/connections/results/2026-09-24-idle-work-binding/precompact-budget-failure.txt)가 되어
35,840 B 상한을 7 B 넘었다. 상한을 올리는 대신 고정 실행 묶음에서는 실행에
필요 없는 ELF 심볼도 제거하도록 했다. 디버깅용 빌드와 소스 작성 묶음은 그대로
두며, `text` 코드 섹션이나 프로세스 RSS가 작아졌다고 주장하지 않는다.
패키지 매니페스트에는 실행마다 달라지는 RSS 표본을 넣지 않고, 크기 상한과
실행물 식별자만 남겼다. 실제 RSS 표본은 별도 검사 JSON에 보관한다.
동일한 의존성 검사를 거쳐 새 위치에서 실제 실행한 결과는 다음과 같다.
| 고정 정의 선택 | 압축 묶음 | 회귀 상한 | 이동 후 동작 |
|---|---:|---:|---|
| [CLI](../../prototypes/connections/results/2026-09-24-idle-work-binding/cli.tar.gz) | 12,987 B | 16,384 B | [검증](../../prototypes/connections/results/2026-09-24-idle-work-binding/cli-check.json) |
| [CLI+HTTP](../../prototypes/connections/results/2026-09-24-idle-work-binding/cli-http.tar.gz) | 28,719 B | 34,816 B | [검증](../../prototypes/connections/results/2026-09-24-idle-work-binding/cli-http-check.json) |
| [CLI+TUI](../../prototypes/connections/results/2026-09-24-idle-work-binding/cli-tui.tar.gz) | 31,726 B | 35,840 B | [검증](../../prototypes/connections/results/2026-09-24-idle-work-binding/cli-tui-check.json) |
| [CLI+HTTP+TUI](../../prototypes/connections/results/2026-09-24-idle-work-binding/cli-http-tui.tar.gz) | 47,419 B | 54,272 B | [검증](../../prototypes/connections/results/2026-09-24-idle-work-binding/cli-http-tui-check.json) |
소스 `.pure`를 묶어 실행 시 정의를 읽는 [작성 CLI 묶음](../../prototypes/connections/results/2026-09-24-idle-work-binding/source-cli.tar.gz)은
22,595 B이고 [이동 후 편집·복원](../../prototypes/connections/results/2026-09-24-idle-work-binding/source-cli-check.json)을
확인했다. 고정 정의 묶음과 기능·크기를 동등한 것으로 취급하지 않는다.
앞선 [047의 CLI+TUI 묶음](047-bounded-native-document-browser.md)은 35,642 B였다.
현재 묶음은 코어 기능이 늘어난 뒤에도 3,916 B 작다. 이 차이는 패키지에서
사용하지 않는 심볼을 제거한 효과다. 작성 CLI와 고정 정의 네 선택을 각각 다시 빌드한
[아카이브 바이트 해시](../../prototypes/connections/results/2026-09-24-idle-work-binding/package-reproducibility.json)도
일치했다. 프로그램 실행 메모리 절감은 위 1,000개 앱 A/B에서 별도로 확인했다.
[기본 릴리스 검사](../../prototypes/connections/results/2026-09-24-idle-work-binding/release.log),
[선택형 비동기 코어](../../prototypes/connections/results/2026-09-24-idle-work-binding/async-core.json),
[실제 HTTP 쓰기 중 읽기](../../prototypes/connections/results/2026-09-24-idle-work-binding/async-gated.json),
[1,024개 문서 서비스](../../prototypes/connections/results/2026-09-24-idle-work-binding/service-scale.json),
[PTY 문서 편집기](../../prototypes/connections/results/2026-09-24-idle-work-binding/tui.json),
[인증 문서 피어](../../prototypes/connections/results/2026-09-24-idle-work-binding/document-peer.json)가
통과했다. 작성 앱의 [독립 상태·충돌·정의 교체
검사](../../prototypes/workbench/results/2026-09-24-idle-work-binding/native-unit.json),
[C 코드 ASan·UBSan](../../prototypes/workbench/results/2026-09-24-idle-work-binding/native-sanitized.json),
[인증 scalar 피어](../../prototypes/workbench/results/2026-09-24-idle-work-binding/scalar-peer.json)도
통과했다. 공통 코어의 [ASan·UBSan 검사](../../prototypes/connections/results/2026-09-24-idle-work-binding/runtime-sanitized.json)는
대여 중인 슬롯과 오래된 티켓을 포함한다.
이 A/B는 같은 프로세스의 1,000개 **동기 네이티브 앱**에 대한 메모리 결과다.
실제 네트워크 서비스 1,000명 처리량, 불신 코드 격리, macOS RSS를 증명하지 않는다.
Zig 0.15.2 실행 파일이 현재 환경에 없어서 scalar 아카이브를 다시 빌드하지는
못했다. 준비된 정의를 현재 소스로 재생성해 기존 아카이브 프로필과 일치함을
검사했고 A/B 모두 동일한 아카이브를 링크했다. 코어·C 호스트는 현재 소스에서
재빌드했다. 다음 연구에서는 유휴 영역 자체의 200 B와 일반 I/O 계약을 함께
검토해야 하며, 슬롯 절감을 이유로 수명·예산의 귀속을 약화해서는 안 된다.
|