QuickLook-Next 5.2.0
New: low memory mode (tray menu → Options)
This release answers "idle memory looks high". Measured, it is not a leak: it is two warm-ups that
trade memory for a fast first preview, and they are a switch now.
Idle memory, measured on one machine (single 200% display, nothing previewed, sampled after the app
had settled):
| configuration | private bytes | working set |
|---|---|---|
| both warm-ups off (low memory mode) | 64 MB | 130 MB |
| preview window warmed only | 112–118 MB | 199 MB |
| plus the two most-used preview families (default) | 169–179 MB | 258–272 MB |
The warm-ups buy ~200 ms on the very first preview (window) and 100–200 ms on the first preview of
each family (measured: text 289 → 96 ms, image 170 → 100 ms). With low memory mode on, neither
runs from the next start, idle memory returns to the 61–64 MB baseline, and the only cost is one
slower first preview per format. Toggling it shows a short note, because the switch only affects
startup.
The two lower-level settings behind it (WarmUpPreviewFamilies, WarmUpFamilyCount) and the table
above are documented in OPTIONS.md.
Something else this investigation turned up (deliberately not changed, reported instead):
memory does not only start high, it also grows with what you have previewed and stays there.
With default settings: 185 MB idle, 249–262 MB after one Markdown preview, and it does not come back
down. Chromium itself exits within a few seconds of the preview closing (the count of
msedgewebview2 processes belonging to this app's profile is 0 after 12 s) — so what stays is
in-process: the managed large object heap (34 MB measured), WPF's text and font caches, and the
plugins' native libraries. Low memory mode behaves the same way: 66 MB idle → 183 MB after
Markdown → 238 MB after an image. It is a "used once, kept" cache rather than a per-preview leak
(the earlier 20 open/close cycles flattened out at 318 → 321 → 320 → 318 MB), and a good part of it
is file mappings the OS can reclaim under pressure. Going lower would mean releasing content when a
preview closes and forcing a collection, which makes the next preview slower — left for a later
release.
Fixed: the preview did not re-measure its content after the window moved to another screen
Two sides of the same thing:
- dragging the preview to another monitor (same scaling, different resolution) only clamped the
position, it never re-measured the plugin's content size; - upstream #1956: after changing the display
scaling, a Markdown preview laid its content out for the old scale, so the page was smaller than
the window.
Now:
- the plugin's own "fit to the screen" question is asked again — the host remembers the last
SetPreferredSizeFitrequest and re-runs it against the new screen whenever the window lands on
another monitor or the resolution/scaling changes, then clamps to that screen. A size the user
dragged themselves still wins, and fixed-size plugins (the info panel) are unaffected. - WebView2 follows the new scale — a Chromium control keeps the scaling it was created with
(that is the cause of #1956), so a scaling change discards every parked control, and the panel
that is on screen rebuilds and reloads its content.
Honest limitation: this machine has one screen and no mixed-scaling setup, so the multi-screen
behaviour could not be reproduced here. The evidence offered is the code path, the parts that are
unit tested, and the /test-preview-diag placement log (dip/px/at/monitorPx/desktopDip). On a
real machine, change the scaling or drag the preview to another screen and check
preview-rect.txt: the window must stay inside monitorPx and its size must follow the new screen.
Fixed: circled numbers are no longer reported as wrong digits
Measured (clean synthetic page + a real one):
- the engine cannot read circled glyphs: ①–⑤ and ❶–❺ both come back empty;
- cropping a single glyph, inverting it, enlarging it to 220 px and recognising it on its own is
still empty (so recovering the digit is not possible); - on a real page, a filled ① was reported as
0— worse than empty, because it invents a number the
picture does not contain.
Since it cannot be read back, do not print something wrong: a lone 0/O/o in a disc-shaped
box is now treated as an unreadable list marker and dropped. Real digit glyphs are taller than
they are wide (aspect 0.4–0.7) and never match. Measured on that page: 4 glyphs filtered, not one
character of the body text lost; English and mixed-language images have zero false positives
(filtered=0 in the diagnostic). /test-ocr now reports a filtered= count.
Look-alike characters ("亲戚" read as "亲威" on that page) are a model limitation: re-running the
same page at 2× made that line worse, so there is no dictionary-based "correction" here — that would
only change the user's own words into something else.
Verification
- Unit tests 87/87 (nine new: low memory mode 3, plugin re-fit 3, scale broadcast 1, circled
glyphs 2). - End to end: 64 MB idle in low memory mode (179 MB by default) with no warm-up diagnostic written;
png / pdf / md / mp4 all land correctly; the Markdown (WebView2) path logs nothing; the circled
glyph page filters 4 and the English/mixed images are untouched. - Known limitation: the real multi-screen / mixed-scaling behaviour cannot be reproduced on one
screen — see above.
Upgrading
Version 5.2.0. Default behaviour matches 5.1.0 (warm-ups on, first-preview speed unchanged).
Users who would rather have the memory back open tray menu → Options → Low memory mode; it applies
from the next start. Automatic update installs straight over the top.