Skip to content

perf: 스크롤·숨김·글꼴 목록이 남기던 메모리 해제 - #59

Merged
centwon merged 3 commits into
mainfrom
perf/memory-squeeze
Sep 28, 2026
Merged

centwon merged 3 commits into
mainfrom
perf/memory-squeeze

Conversation

@centwon

@centwon centwon commented Sep 28, 2026 •

Copy link
Copy Markdown
Owner

요약

지금까지의 메모리 측정은 전부 맨 위에 놓인 문서를 쟀다. 렌더 경로는 그린 것을 캐시하는데, 끝까지 한 번 넘기면 전부를 그린다. samples/MemBaseline에 스크롤 시나리오를 넣어 처음 쟀다(Release, Intel UHD, Private bytes).

2,000문단 + 사진 100장 전 후
끝까지 스크롤 501 MB 257 MB
다시 맨 위로 499 MB 217 MB
시각 트리에서 뺌(숨긴 탭 등) 482 MB 185 MB
다시 넣음 481 MB 150 MB

변경

  • 화면에서 먼 그림 해제 (ImageCache.TrimOffscreen) — 마지막으로 그려진 컨트롤 좌표 + LRU. 뷰포트 ±1화면은 보호, 밖은 32 MB까지.
  • 레이아웃 캐시 LRU (TrimLayoutCache, 256 + 여유 128) — 드로 패스 끝에서만(쥐고 있는 레이아웃이 없는 시점).
  • Unloaded 해제 — 레이아웃 전부, 화면에서 먼 그림.
  • CanvasDevice.Trim — 비트맵 해제 2초 뒤 한 번(~0.7 ms). Private 38 MB·GPU 70 MB 추가 회수.
  • 글꼴 목록 — 면 단위 순회(+31.6 MB, 843 ms) → GetSystemFontFamilies(string[])(+0.7 MB, 140 ms, 이름 동일).
  • 이미지 교체 뒤 레이아웃을 Dispose 없이 버리던 곳 수정.
  • Document 속성 주석: 직접 대입은 변경으로 친다(Load*/MarkSaved 안내).

검증

  • 테스트 951 통과(+12, ControlMemoryTrimTests). 반증 15종 전부 빨강.
  • AOT 함정 2개를 JIT/AOT 프로브가 잡았다(JIT 테스트는 둘 다 통과): CanvasFontSet.GetPropertyValues(비blittable 구조체 배열)와 컬렉션 식 로캘 목록(CCW 생성 실패). 둘 다 조용히 기본 글꼴 6개로 폴백. 데모 --pageprobe에 fonts 줄 추가 — 수정 후 JIT/AOT 출력 바이트 동일, AOT 전용 fault는 기존 LineMetricsOf 하나.
  • 측정으로 레버가 아님을 확인: 고정비 ~37 MB는 전부 Win2D(맨 CanvasVirtualControl 111.6 MB > 빈 에디터 108.3 MB).

남은 것

  • 실기 확인(2026-09-28, 사용자 — 문제 없음): 사진 많은 문서를 끝까지 스크롤했다 돌아올 때 자리표시(재디코드)가 거슬리는지, 탭 전환 뒤 그림이 바로 보이는지, 툴바 글꼴 목록이 전부 나오는지
  • fault-sweep 전체(입력 주입)는 게시 전 체크리스트에서

🤖 Generated with Claude Code

centwon and others added 3 commits September 27, 2026 14:00
지금까지의 메모리 측정은 맨 위에 놓인 문서만 쟀다. MemBaseline에 스크롤
시나리오를 넣어 처음 쟀다(2,000문단 + 사진 100장, Private bytes):
끝까지 스크롤 501 → 257 MB, 맨 위 499 → 217, 트리에서 뺌 482 → 185,
다시 넣음 481 → 150.

- ImageCache.TrimOffscreen: 그림마다 마지막으로 그려진 컨트롤 좌표와
  사용 순서를 기록하고, 드로 패스 끝에서 뷰포트 ±1화면 밖을 LRU로
  32 MB까지 해제한다. 다시 보이면 다시 디코드한다.
- 레이아웃 캐시 LRU: 드로 패스 끝에서 최근 256개로(여유 128). 스크롤하면
  2,000문단 전부를 2048 clear-all까지 들고 있었다.
- Unloaded: 레이아웃 전부와 화면에서 먼 그림을 놓는다.
- 그림 해제 2초 뒤 CanvasDevice.Trim (드라이버 스테이징 메모리).
- 글꼴 목록: 면 단위 순회(+31.6 MB, 843 ms) 대신
  GetSystemFontFamilies(string[]) (+0.7 MB, 140 ms, 같은 이름).
  GetPropertyValues(비blittable 구조체 배열)와 컬렉션 식 로캘 목록은
  AOT에서 조용히 실패했다 — 데모 --pageprobe에 fonts 줄을 넣어 잡았다.
- 이미지 교체 뒤 레이아웃 캐시를 Dispose 없이 비우던 곳 수정.

테스트 +12(951 통과), 반증 15종 전부 빨강, JIT/AOT 프로브 바이트 동일.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Load*는 변경 없음(되돌리기 기록도 비움), Document에 직접 대입하면(코드·바인딩)
IsModified가 true가 된다 — 에디터는 파일에서 온 문서와 코드로 만든 문서를 구별할
수 없다. 바인딩으로 문서를 넣는 호스트가 열자마자 "*"를 보고 놀라지 않게.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@centwon
centwon merged commit 9d65631 into main Sep 28, 2026
2 checks passed
@centwon
centwon deleted the perf/memory-squeeze branch September 28, 2026 10:53
centwon added a commit that referenced this pull request Sep 29, 2026
fix: 레이아웃 LRU가 그 패스 자신의 작업 집합을 자르던 것 (#59 감사)
centwon added a commit that referenced this pull request Sep 30, 2026
상류 PR #59·#61의 20건을 여기서 먼저 쟀다. 14건이 이 포트에도 있었다.

- HTML <div> 2,000겹(11 KB) -> WalkBlocks 스택 오버플로(0xC00000FD). DOM 128단 아래는 글자로 접기,
  HtmlAgilityPack id 색인 끔(그 서브트리 제거가 재귀)
- 인라인 표 셀로 끝나는 선택 삭제가 그 줄 전체(표 포함)를 지움 (TextRange.CoveredSpan)
- Document 대입 뒤 Ctrl+Z가 옛 파일을 되살림 -> _applyingHistory가 아니면 기록 비움
- JSON/.flow 그림 MIME이 내보낸 HTML <img src>에 그대로 -> 읽기·쓰기 모두 검증
- 가져오는 표 1,000열/25만 셀 (JSON·HTML·RTF, RTF 합집합 List.Contains O(n^2)도)
- .flow 미참조 그림 항목 안 읽음, 항목당 256 MB
- HTML 넓은 행 예외 · ListLevel -1/100만 · 문단 안 script/style ·
  JPEG 채움 바이트 · 병합 앵커가 중첩 표로 시작 · RTF 글꼴명 ';'

이미 맞던 것(가드 테스트만): InsertTable 음수·0, 한 문단 붙여넣기, 행 없는 인라인 표,
RTF 깊은 중첩, RTF 병합 속도, 그림 폭탄 메모리(WIC 스트리밍 축소 — 상류의 픽셀 상한은 안 들여옴).

테스트 953 -> 980, 수정마다 개별 반증(깊이 둘은 호스트 0xC00000FD 사망으로 확인).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant