[English] | 简体中文
All numbers from the author's machine (Apple Silicon, 6P+12E cores),
measured after a cooldown, release profile with
target-cpu=native. The benchmark harness is kept out of the published tree (local APK paths); the tables
above are the recorded results.
Recorded 2026-10-22 with v0.1.33: one run per cell after a short settle; the previous table was recorded on an earlier (pre-cure) version; full and --fast are now separate columns. Peak RSS is /usr/bin/time -l.
Seven real-world APKs — reqable 3.2.23 (34MB), Telegram (62MB), WhatsApp
(139MB), weibo 16.9.1 (226MB, 20 dex), weixin 8.0.78 (268MB), lark 8.0.2
(398MB, 59 dex), qq 9.3.65 (374MB) — wall time, peak RSS via /usr/bin/time -l,
measured after a cooldown:
| APK | Size | Full decompile | --fast |
Peak RSS (full) |
|---|---|---|---|---|
| reqable | 34 MB | 0.83s | 0.50s | 280 MB |
| Telegram | 62 MB | 6.91s | 4.08s | 924 MB |
| 139 MB | 24.98s | 11.41s | 1067 MB | |
| 226 MB | 21.03s | 10.87s | 1380 MB | |
| weixin | 268 MB | 40.21s | 25.29s | 1497 MB |
| lark | 398 MB | 26.29s | 14.61s | 2406 MB |
| 374 MB | 57.00s | 31.96s | 2511 MB |
Compile validation — read the scope before quoting this number:
every .java of all seven APKs (909,689 files) passes javac's parse
gate (-XDshould-stop.ifNoError=PARSE -XDshould-stop.ifError=PARSE)
with zero syntax errors. That gate stops at the parser: it does NOT
type-check, resolve symbols, or guarantee the output compiles against a
classpath.
Semantic quality is measured separately — a javac battery with the full Android classpath (android-37 jar + optional libraries) over four corpora, counting ddc-attributable diagnostics. That battery is the driver of the post-0.1.4 fix rounds and has gone 11,345 → 7,452 errors (−34%) from v0.1.19 to v0.1.22, including a multi-handler exception-routing bug present since the first release (every catch of a multi-handler method ran the first handler's code — invisible to any parse gate) and three javac-blind value-loss defects found by reading the output against the disassembly. Semantic quality still trails jadx on type recovery (erased generics, register-typed locals in R8 monster methods) — see "Known limitations" in the README.
Measured after a cooldown; cells are wall time / peak RSS. Query targets:
strings -f <package> --with-locations; findrefs string <package>;
findrefs method onCreate; hierarchy/disasm/getclass use each
app's launcher class (Telegram's LaunchActivity is an exceptionally
large class):
| Command | reqable | Telegram | weixin | lark | |||
|---|---|---|---|---|---|---|---|
info |
0.24s / 55MB | 0.41s / 117MB | 0.85s / 316MB | 1.32s / 569MB | 1.61s / 602MB | 2.46s / 969MB | 2.30s / 1145MB |
listclasses |
0.02s / 25MB | 0.03s / 89MB | 0.04s / 96MB | 0.14s / 337MB | 0.16s / 371MB | 0.18s / 251MB | 0.24s / 311MB |
manifest |
0.00s / 12MB | 0.00s / 19MB | 0.00s / 26MB | 0.01s / 48MB | 0.01s / 37MB | 0.01s / 34MB | 0.01s / 54MB |
mainactivity |
0.02s / 20MB | 0.06s / 72MB | 0.08s / 136MB | 0.17s / 199MB | 0.18s / 199MB | 0.22s / 226MB | 0.31s / 300MB |
res |
0.00s / 12MB | 0.00s / 20MB | 0.00s / 27MB | 0.02s / 56MB | 0.01s / 37MB | 0.01s / 36MB | 0.01s / 57MB |
largest |
0.02s / 28MB | 0.05s / 71MB | 0.13s / 195MB | 0.32s / 363MB | 0.30s / 346MB | 0.46s / 519MB | 0.66s / 631MB |
strings |
0.02s / 20MB | 0.04s / 55MB | 0.12s / 117MB | 0.23s / 177MB | 0.28s / 198MB | 0.18s / 192MB | 0.49s / 295MB |
findrefs-string |
0.02s / 31MB | 0.03s / 74MB | 0.04s / 203MB | 0.06s / 397MB | 0.08s / 425MB | 0.04s / 322MB | 0.10s / 849MB |
findrefs-method |
0.02s / 31MB | 0.05s / 81MB | 0.04s / 212MB | 0.06s / 374MB | 0.07s / 448MB | 0.07s / 581MB | 0.11s / 917MB |
members |
0.01s / 19MB | 0.03s / 55MB | 0.05s / 118MB | 0.11s / 174MB | 0.11s / 180MB | 0.14s / 218MB | 0.21s / 285MB |
hierarchy |
0.01s / 20MB | 0.03s / 55MB | 0.05s / 127MB | 0.10s / 174MB | 0.11s / 177MB | 0.15s / 194MB | 0.21s / 294MB |
disasm |
0.01s / 19MB | 0.03s / 58MB | 0.05s / 124MB | 0.10s / 175MB | 0.11s / 182MB | 0.14s / 193MB | 0.20s / 281MB |
getclass |
0.02s / 33MB | 0.21s / 131MB | 0.18s / 256MB | 0.41s / 515MB | 0.50s / 527MB | 0.70s / 830MB | 1.30s / 1200MB |
- Serial runs after a cooldown. Same-machine variance reaches ±25% (E-core scheduling + memory bandwidth contention); a single run proves nothing.
/usr/bin/time's user time includes all threads — a "busy" worker is not CPU (write-back-pressured threads tick wall time without cycles). Look at user+sys ÷ effective cores vs wall; the gap is scheduling/blocking.- Wall-clock critical paths migrate: first CPU, then disk writes, then deadline idling on timed-out classes. Re-profile every round; don't keep optimizing the old hotspot.
DDC_PHASES=1(phase timings, cumulative — difference them) andDDC_BUCKETS=1(per-class by block count) answer "which methods eat CPU" more directly than stack sampling;sample <pid> 3 -fileearly and late (different phases, different hotspots) when you need line-level attribution. RSS curves viaps -o rss= -p $PIDevery 5s locate the allocation phase (lark: 733MB at t=5s → 2086MB at t=10s = materialize peak, before any retirement fires)./usr/bin/time -lreports RSS in bytes, not KB.
Five real APKs (62–353 MB), progressive queries, stdout discarded; correctness cross-checked: 107/107 hits coincide:
| Query | ddc | ASC | Ratio |
|---|---|---|---|
| findrefs string (lark 353MB) | 0.32s | 0.61s | 1.9× |
| findrefs string (weixin 268MB) | 0.22s | 0.52s | 2.4× |
| findrefs string (weibo 226MB) | 0.19s | 0.44s | 2.3× |
| findrefs type/method (all five) | 0.09–0.31s | 0.29–0.66s | 2–3× |
| getclass (lark/weixin/weibo) | 0.18–0.42s | 0.10–0.12s | ASC wins |
| getclass (Telegram, big class) | 0.05s | 0.11s | ddc wins |
| findrefs memory (lark) | ~820MB | ~170MB | ASC leaner |
The getclass split: ASC bit-stream-probes the zip to inflate only the
target dex (a lower floor on huge multi-dex APKs); ddc parses all image
headers (~0.2s floor) then materializes lazily — it overtakes when the
class itself is expensive, loses to the floor when it isn't. On findrefs
scan domains ddc is uniformly faster (pipeline: parse waves → bounded
channel → scan threads consume-and-drop; Arc-shared APK bytes eliminate
compression copies).