Skip to content

Should vfox-plus go with mygo, still the implementation with the lowest memory usage? #11

Closed

Description

@linghengqian
Implementation Technology Processes Home PSS Home RSS Versions PSS Versions RSS The list adds (PSS)
mygo mygo 0.6, Go 1.27.3, GTK 3 (purego), CPU renderer 1 41 54 47 60 +6
Uno Uno Platform 6, C# on .NET 10, Skia on the CPU, Native AOT 1 98 106 113 122 +15
Compose Compose Multiplatform, Kotlin on JDK 25.0.5+8, Gradle 9.8.2, Skia on the CPU, C1 only 1 129 135 152 158 +23
Gio Gio, Go 1.27.3, OpenGL ES through EGL 1 165 202 171 208 +6
Flutter Flutter 3.47.8, Dart 3.13.7, Skia on the CPU, GTK 3 2 172 212 183 223 +11
Dioxus Dioxus 0.7, Rust, Node.js 24.22.1 front-end build, WebKitGTK, no compositing, DMA-BUF or JIT 3 203 385 220 402 +17
Tauri Tauri 2, Rust, Node.js 24.22.1 front-end build, WebKitGTK 4.1 (GTK 3), no compositing, DMA-BUF or JIT 3 208 382 220 394 +12
Flet Flet, Python 3.14 in a Flutter application, uv 0.13.5, Skia on the CPU 2 216 257 224 266 +8
Wails Wails 3, Go 1.27.3, Node.js 24.22.1 front-end build, WebKitGTK 6.0 (GTK 4), as Tauri, GTK OpenGL off 3 223 408 237 431 +14
Capacitor Ionic Vue and Capacitor in Electron, Node.js 24.22.1 front-end build, no GPU process, no V8 JIT 4 267 468 281 487 +14
  • How it was measured: Ubuntu 26.04 in Docker, Xvfb at 1280x800, no GPU, and a fake vfox that replays captured output. shared/tools/measure.sh sums Rss and Pss from /proc/<pid>/smaps_rollup over the process tree of the app once each page has settled. Flutter has no in-app scenario for this, so flutter/tool/measure.py clicks through its release build with XTEST instead. Pull requests that rebuild an implementation get a comment with the same table, measured on the runners of GitHub, with the difference from main (Comment the memory of every implementation on pull requests #21).
  • PSS is the column to compare. RSS counts a shared page once for every process that maps it, which is why Capacitor has 468 MB of RSS but 267 MB of PSS over four processes.
  • Without a GPU, everything that draws with OpenGL loads Mesa's llvmpipe, and that memory is in the numbers (the Gio README says it is most of what Gio uses). Uno is set to draw with Skia on the CPU instead; with Mesa's software GL the same Uno build took about 130 MB more. mygo draws on the CPU too, and the app tells GDK not to open OpenGL: the same build took about 78 MB with it and about 43 MB without. Lower the memory of Capacitor, Tauri, Dioxus, Wails and Uno #20 found the same cost in the web views and in Electron, even on pages this size: WebKitGTK enters accelerated compositing mode, and Electron's GPU process opens, unless told not to, and both map Mesa's software GL the same way. Turning that off (WEBKIT_DISABLE_COMPOSITING_MODE=1 before the webview starts, app.disableHardwareAcceleration() before Electron's window) took Tauri from 419 to 275 MB, Dioxus from 427 to 258, Wails from 482 to 346 and Capacitor from 388 to 303; all four now do this. Lower the memory of Compose, Flutter, Flet, Gio, Tauri, Dioxus, Wails and Capacitor #22 went on with these and with the rest, each change measured against the build without it on the same day: Compose draws with Skia on the CPU (-Dskiko.renderApi=SOFTWARE) and runs the JVM with the first compiler of its JIT only (-XX:TieredStopAtLevel=1), about 50 MB each, 253 to 129 MB; Flutter sets FLUTTER_LINUX_RENDERER=software and turns Impeller off, 339 to 172 MB and a tenth of the processor time until the Home page, and Flet only needs the variable, about 340 to 216 MB; Tauri, Dioxus and Wails also turn off the DMA-BUF renderer and the JIT of WebKit (WEBKIT_DISABLE_DMABUF_RENDERER=1, JSC_useJIT=false), 262 to 208 and 261 to 203 MB, and Wails keeps GTK 4 from opening OpenGL (GDK_DISABLE=gl,vulkan, GSK_RENDERER=cairo), 341 to 223 MB; Capacitor keeps the GPU and the network service in the browser process and runs V8 in lite mode, 305 to 267 MB and from six processes to four; Gio keeps one copy of the tables of its variable font instead of three and lets its heap grow 25 % between collections, which takes the heap of Go from 57 to 20 MB, inside a number that varies by 20 MB. I found nothing more to take out of mygo and Uno. On Wayland, GDK opens OpenGL for the windows of GTK 3 unless told not to, which Tauri, Dioxus, Flutter and Flet now do (Tauri on a headless sway: 242 MB without it, 207 with it); the table is measured on X11. What is still created without a GPU is the OpenGL contexts of the engine of Flutter and of the processes of WebKit, which cannot start without EGL, and Gio draws with OpenGL, so on a machine with a GPU the numbers of those, and maybe the order, will be different.
  • Lower the memory of Compose, Flutter, Flet, Gio, Tauri, Dioxus, Wails and Capacitor #22 was not tested with a real GPU, with GNOME or with the bubblewrap sandbox of WebKitGTK (WebKit's source says that it passes the variables on), and the frame rate of the processor renderers of Compose, Flutter and Flet on a large or HiDPI window has not been checked.
  • Each row is one run, and the ten were measured one after another with nothing else running. Gio varies by some 20 MB between runs of the same build, and Flutter was measured six times on an earlier day, when its home page PSS ranged from 332 to 342 MB, so a difference of a few MB means nothing. CPU usage has not been measured yet.
  • Wails was suggested in [Feature]: Using GUI to manage SDK versions vfox#371 (comment) as a lighter option than Electron. On Linux, now that the GPU-dependent paths above are off everywhere, it is at 223 MB, below Capacitor, which runs in Electron (267 MB, the highest of the ten), as that comment expected, and close to Tauri (208) and Dioxus (203). WebKitGTK 6.0 with GTK 4, which Wails uses, still needs 15 MB more than the WebKitGTK 4.1 with GTK 3 that Tauri uses for the same front end; it was 71 MB more before Wails kept GTK 4 from opening OpenGL. On Windows, Wails, Tauri and Dioxus use WebView2 instead, which none of this covers.
  • All ten only run on the Linux desktop for now. None of them has been built for Windows (.msixbundle) or Android (.apk) yet, which Impl the WebUI and desktop app for vfox using multiple technology stacks, based on the Material Design 3 Expressive design language #1 asks for. As far as I know, mygo is the only one without an Android target, see its known issues.
  • Known issues of each implementation, as far as I know,
    • mygo
      • It is young: 0.6.3 at the time of writing, and its API changes. The version is pinned.
      • No Android target. It has backends for Linux, Windows, macOS and browsers, and GOOS=android CGO_ENABLED=0 go build fails. It does compile to WebAssembly and draws in browsers (this app builds for js/wasm, 13.6 MB or 3.5 MB compressed, and WebKitGTK shows it), but a browser cannot start vfox. So a web UI, or an .apk that is a web view around it, would need a remote process runner and an agent on the machine that runs vfox. None of that is written.
      • Windows: the app compiles for it, but core, which Gio has as well, assumes Linux where it stops a process, splits PATH, looks for vfox and keeps the settings. mygo build makes an exe and an NSIS installer, not an MSIX, so the .msixbundle would be packed with MakeAppx.exe of the Windows SDK. Not tried.
      • Wayland works through GTK 3: on a headless sway the app id matches the desktop entry. Not tried on GNOME.
      • mygo registers ATK objects, which GTK bridges to AT-SPI, so Orca should see the window. Input methods are those of GTK 3 (IBus, Fcitx, the Wayland text input). Neither has been tried.
      • It renders on the CPU (see above), and its CPU load during animations has not been measured. The slowest frames I saw in the sandbox took 14 to 36 ms.
      • Scaling is GTK 3's, whole numbers only. The title bar is the desktop's, not Material 3 Expressive.
      • Like Uno and Gio, every Material 3 Expressive control is our own code (mygo/ui/kit), with the color utilities and the shapes copied from Gio.
      • On the first start it writes the two icon fonts (36 KB) to ~/.cache/mygo/fonts/, because fontconfig only loads fonts from files.
    • Uno
      • No Wayland backend. The window is an X11 window, through XWayland on a Wayland desktop. The display scale comes from Xft.dpi or UNO_DISPLAY_SCALE_OVERRIDE, and without either it is drawn at scale 1. Only scales 1 and 2 have been tried.
      • Screen readers cannot see the window, because Uno's X11 host does not talk to AT-SPI. Keyboard navigation works.
      • Uno's X11 host supports IBus and Fcitx, but neither has been tried.
      • It renders on the CPU (see above), and its CPU load during animations has not been measured.
      • Uno's themes do not look like Material 3 Expressive, so every Material 3 Expressive control is our own C# code on WinUI's panels, including ports of the Material color utilities and of androidx.graphics.shapes.
      • Once, in a sandbox run under heavy load, part of the previous page stayed on screen after a page switch and a rail expansion. It did not happen again in about 8 later runs.
    • Gio
      • No AT-SPI either, so screen readers cannot see the window. Keyboard navigation works.
      • GNOME on Wayland leaves the title bar to the app, so the app draws its own. Double-clicking it does not maximize the window, because Gio hands the press to the compositor for the move.
      • Noto Sans CJK only has Regular and Bold, so Chinese text in the other weights of the type scale uses the nearest one.
      • Input methods only work through IBus on X11 and text-input-v3 on Wayland.
      • Like Uno, every Material 3 Expressive component is our own code (gio/ui/kit), with Go ports of the color utilities and the shapes.
    • Compose
      • AWT makes it an X11 window, so it also runs through XWayland on a Wayland desktop.
      • It renders on the CPU and compiles with the first compiler of the JIT only (see above), which took about half of its processor time in the sandbox. Its frame rate on a large or HiDPI window has not been checked.
    • Flutter
      • The second process is glycin-svg, which gdk-pixbuf starts to load the SVG icon of the window. It takes 18 MB of RSS, and without that icon (the desktop entry gives the window its icon once the package is installed) the application would take about 18 MB less, in one process.
      • It renders on the CPU with Skia (see above), and its frame rate on a large or HiDPI window has not been checked.
    • Flet
      • It renders on the CPU with Skia too, through a patch of the cached Flet build template, and its frame rate has not been checked either.
      • Resizing the window at run time crashes the renderer from time to time on an X server without a window manager (seen under Xvfb). As a workaround, the cached Flet build template is patched so that the window opens at 1280x820 and never resizes itself at start-up.
      • flet build has no offline mode, so a build always needs the network.
      • Flet only has Flutter's Material widgets, so the Material 3 Expressive parts are in our own Flet extension (flet/m3e, Python and Dart). It has to stay on Flet's Flutter 3.44.8, while the Flutter implementation is on 3.47.8.
    • Capacitor
      • Capacitor has no Linux platform, and its community Electron platform only supports Capacitor 5 and has not been updated since 2023. So on Linux this is Ionic Vue in an Electron shell of our own, with one Capacitor plugin as the bridge to the main process.
      • The .tar.gz cannot keep chrome-sandbox setuid root. After unpacking it, users need sudo chown root:root chrome-sandbox && sudo chmod 4755 chrome-sandbox, or vfox-plus --no-sandbox.
      • Text fields in dialogs keep Ionic's outlined style under their floating labels, while the other text fields are filled as in Flutter.
      • The GPU and the network service run inside the browser process (--in-process-gpu, NetworkServiceInProcess2), so a failure in either one is a failure of the app, and V8 leaves out its optimizing compiler (--js-flags=--lite-mode). Only the pages of this app have been tried with that.
    • Tauri and Dioxus
      • Nothing known beyond what WebKitGTK costs for the long list (+12 MB for Tauri, +17 MB for Dioxus, now that accelerated compositing is off).
      • Their WebKit runs without its JIT and without the buffers that it shares with the GPU (see above). The end-to-end scenarios pass and the responsiveness did not change in them, but only the pages of this app have been tried.
    • Wails
      • Wails 3 is still in beta (v3.0.0-beta.34 here).
      • GTK 4 draws with Cairo and without OpenGL (see above), and WebKit has the settings of Tauri and Dioxus.
      • WebKitGTK 6.0 confines its web processes with bubblewrap, which needs user namespaces. CI and the Docker sandboxes do not have them and set WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1, so the confined mode, which is what users get on a desktop, is not covered by any test.
  • On the license requirement of Impl the WebUI and desktop app for vfox using multiple technology stacks, based on the Material Design 3 Expressive design language #1: Tauri and Dioxus ship option-ext (MPL-2.0) through wry. Capacitor ships Chromium's FFmpeg (libffmpeg.so, LGPL-2.1). Flet ships the Dart packages dbus, nm and upower and the Python package certifi (all MPL-2.0), which Flet itself pulls in. Compose ships a Java runtime made with jlink (OpenJDK, GPL-2.0 with the Classpath Exception). Gio, Uno and mygo have no copyleft dependency (mygo loads the GTK 3 of the system, which is under the LGPL, and does not ship it).

Activity

  1. linghengqian commented on Oct 18, 2026

    @linghengqian
    MemberAuthor

    I’d like to open this up for a broader discussion. What are your thoughts? CC @zealcc @jan-bar @ShizheChang @yeshan333 @axdank @ahai-code @yanecc @bytemain @Chance-fyi @aooohan .

  2. yeshan333 commented on Oct 18, 2026

    @yeshan333
    Member

    Try mygo?

  3. linghengqian commented on Oct 18, 2026

    @linghengqian
    MemberAuthor

    Try mygo?

    • On Linux, it seems that for "mygo" to implement the Material 3 Expressive design language, it has to use WebKitGTK. Does this mean that—much like Wails—it ends up consuming over 400 MB of RAM? This is my first time hearing about "mygo"; am I missing something here? I am testing locally.

    Each MyGo window shows one of two kinds of interface, and one app, or one window, can mix them:

    A web page, in the webview the OS already has: WKWebView on macOS, WebKitGTK on Linux, WebView2 on Windows. Build the frontend with any web tools; it calls your Go code through a TypeScript client generated from it.

    Native UI, written in Go alone with package ui and drawn by MyGo itself on the GPU: no HTML, no JavaScript and no webview, so the window opens at once and takes little memory.

  4. changed the title [-]Should vfox-plus go with Uno, the implementation with the lowest memory usage?[/-] [+]Should vfox-plus go with mygo, the implementation with the lowest memory usage?[/+] on Oct 19, 2026
  5. linghengqian commented on Oct 19, 2026

    @linghengqian
    MemberAuthor
  6. aooohan commented on Oct 19, 2026

    @aooohan
    Member

    We only need to support PC ;)

  7. changed the title [-]Should vfox-plus go with mygo, the implementation with the lowest memory usage?[/-] [+]Should vfox-plus go with mygo, still the implementation with the lowest memory usage?[/+] on Oct 19, 2026
  8. linghengqian commented on Oct 19, 2026

    @linghengqian
    MemberAuthor
    • Lower the memory of Capacitor, Tauri, Dioxus, Wails and Uno #20 (merged) turned off GPU-dependent rendering in Capacitor, Tauri, Dioxus and Wails, and switched Uno to Native AOT. Updated numbers: https://github.com/version-fox/vfox-plus/blob/045a56727d2667ba398783ce99f4cbec52b609b5/docs/memory.md . mygo is still clearly the lowest, now under half of what Uno uses instead of a third.
    • I'll keep looking for more memory to cut over the next few days. If nobody suggests a different stack worth trying by Saturday, October 24, I'm going to start removing the implementations other than mygo from main.
    • One caveat on all of this: I develop locally on WSL2, so I have no real GPU to test any of it against — WSL2's GPU passthrough goes through Mesa's D3D12 ("dozen") driver, which isn't good enough to trust here 🙃. So the GPU-dependent paths stay untested on real hardware for now; that will have to wait for a Windows build of whatever is left to test against. GitHub Actions' free runners have no GPU either — it's a paid "larger runner" feature on Team/Enterprise plans, not something public repos get for free — so CI won't cover it either.
  9. linghengqian commented on Oct 24, 2026

    @linghengqian
    MemberAuthor
  10. linghengqian commented on Oct 24, 2026

    @linghengqian
    MemberAuthor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions