Skip to contentSkip to content

CLI Subprocess, Memory, and Recovery

Use this page when translating a large batch at once and memory consumed by models and intermediate results keeps growing during a long run. The local subprocess mode runs each batch in an independent subprocess while the parent process only collects files, assigns batches, and gathers results. When --memory-limit, --memory-percent, or --batch-per-restart is reached, the current subprocess exits early and a new subprocess continues with the remaining files; files that already completed are not translated again.

This guide focuses on the local --subprocess subprocess, memory-limit, and recovery mechanics. Ordinary (non-subprocess) local translation is in Local input and output; command structure and the official entry point are in Command structure; configuration overrides are in Configuration overrides; output and exit codes are in Output, debugging, and exit codes.

Command scope

  • --subprocess changes only the local execution path: file collection, output directory, and skip-existing logic match the normal mode, but translation runs batch by batch inside a multiprocessing.Process subprocess.
  • --memory-limit, --memory-percent, and --batch-per-restart are consumed only when --subprocess is enabled; the plain local path ignores all three.
  • “Recovery” has three layers here: after an in-run memory limit is hit, a new subprocess continues; after a subprocess exception, the same batch is retried automatically; re-running without --overwrite skips files whose output already exists. The official top-level local has no usable cross-run --resume option; see the --resume parameter.
  • This guide does not cover cli.attempts (API-call retries), API candidate-slot rotation (see the API-management pages), cli.batch_size/cli.batch_concurrent (batch concurrency, see CLI batch and output), or the web/ws/shared service modes (see Web, WS, and shared modes).

Command-line operations

Enable subprocess mode

From the repository root, call with the project-managed runtime:

powershell
uv run --no-sync python -m manga_translator local -i ./manga_folder/ --subprocess
  • -i/--input is required and may be given multiple times; folders are scanned recursively for images and individual files are processed in natural name order.
  • -o/--output sets the output directory; when omitted, the parent uses app.last_output_path from configuration, then the input folder plus a -translated suffix, then the directory of the first input file.
  • --config selects a configuration file; a load failure prints an error and exits (code 1).
  • Without --overwrite, the parent first pre-filters files whose output already exists; only the remaining files enter subprocesses.

Set memory and restart thresholds

  • Limit only the subprocess's own memory and restart above 4000 MB: --memory-limit 4000.
  • Limit only the system-memory share and restart above 85%: --memory-percent 85.
  • Restart a subprocess every 20 images to release memory: --batch-per-restart 20.
  • Set an absolute memory limit and a per-batch count together: --memory-limit 6000 --batch-per-restart 30.
powershell
uv run --no-sync python -m manga_translator local -i ./manga_folder/ --subprocess --memory-limit 4000
uv run --no-sync python -m manga_translator local -i ./manga_folder/ --subprocess --memory-percent 85
uv run --no-sync python -m manga_translator local -i ./manga_folder/ --subprocess --batch-per-restart 20
uv run --no-sync python -m manga_translator local -i ./manga_folder/ --subprocess --memory-limit 6000 --batch-per-restart 30

See Parameters and options for threshold semantics and official defaults. The absolute and percent limits can be set at the same time and both are checked; they are not the same metric.

Parameters and options

For the UI-copy and storage-key correspondence shared with desktop settings, see the UI Options Reference.

--subprocess

Add --subprocess to enable subprocess mode: each batch runs in an independent subprocess while the parent process only collects files, assigns batches, and gathers results; when a memory or batch-count threshold is reached, the current subprocess exits early and a new subprocess continues with the remaining files, and files that already completed are not translated again. Options: --subprocess (enabled) or omitted (disabled, default). Default: false.

--memory-limit

Limits the memory usage of the subprocess itself (in MB): when the threshold is exceeded during processing, the current subprocess exits early and the remaining files are handed to a new subprocess. Options: positive integers (MB); 0 means unlimited. Default: 0.

--memory-percent

Limits the share of system memory: when whole-machine memory usage exceeds the threshold, the current subprocess exits early and the remaining files are handed to a new subprocess. Options: positive integers (percent); 0 means unlimited. Default: 0.

--batch-per-restart

Restarts a subprocess after every N images to release memory. Options: positive integers (image count); 0 means no restart by image count (all pending files are processed in one run). Default: 0.

--resume

The resume flag exists only in the standalone module parser (python -m manga_translator.mode.local --help); the official top-level local has no such option, so do not rely on it for cross-run continuation. Cross-run recovery actually relies on the pre-filter that skips files whose output already exists when --overwrite is not set; use --overwrite to re-translate files that already exist. Options: --resume (declared) or omitted. Default: false (not present in the official parser).

How the command runs

Parent scheduling loop

The subprocess branch of run_local_mode() hands all inputs to translate_with_subprocess(). It keeps a completed_files set as the in-run “checkpoint”: each round it takes up to batch_per_restart files from the pending list (0 means all), starts a subprocess, waits for the result queue, merges completed files into the set, and loops until no pending files remain.

flowchart TD
    A["Collect inputs: recursive folders + single files, natural sort"] --> B["Resolve output dir: -o → app.last_output_path → input folder -translated"]
    B --> C{"--overwrite not set?"}
    C -->|yes| D["Pre-filter files whose output already exists"]
    C -->|no| E["All files enter the pending list"]
    D --> F{"Pending list empty?"}
    E --> F
    F -->|yes| Z["Finish: print success/failure counts and return"]
    F -->|no| G["Take up to batch_per_restart files (0=all)"]
    G --> H["Start multiprocessing.Process subprocess"]
    H --> I["Wait on result_queue, timeout = file count × 600 s"]
    I --> J{"Success result received?"}
    J -->|yes| K["Accumulate success/failure and merge completed_files"]
    J -->|no| L["Print batch error; on queue-read failure count the whole batch as failed"]
    K --> F
    L --> F

Inside the subprocess, each image goes through translate_batch: Config is built only from the explicit keys render/upscale/translator/detector/colorizer/inpainter/ocr plus kernel_size, mask_dilation_offset, and force_simple_sort; cli.verbose/cli.overwrite are written back into configuration and font_family is copied to the top level; each image handle is closed immediately after processing.

Memory check and early exit

After each image, the worker reads “own RSS” and “system memory percent” (both via psutil) and independently checks the two thresholds; if either is exceeded it returns the completed list early without processing the remaining files. The parent hands the remaining files to a new subprocess in the next round and increments restart_count.

flowchart LR
    A["Subprocess finished one image"] --> B["Read own RSS and system memory percent"]
    B --> C{"memory_limit_mb > 0 and RSS above threshold?"}
    C -->|yes| D["Return completed/failed lists early"]
    C -->|no| E{"memory_percent > 0 and system percent above threshold?"}
    E -->|yes| D
    E -->|no| F["Continue with the next image"]
    D --> G["Parent puts remaining files into a new batch and starts a new subprocess"]
  • Display rule: when --memory-limit > 0 only the absolute threshold is shown; otherwise when --memory-percent > 0 the percent and its approximate MB value are shown; when --batch-per-restart > 0 the per-batch count is shown.
  • When both limits are set they are both enforced: --memory-limit watches the subprocess's own RSS while --memory-percent watches whole-machine memory usage; they are not the same metric.
  • When psutil is unavailable both readers return 0, the memory checks are skipped entirely, and only the image-count restart remains.

Failure and recovery

Results travel between the subprocess and the parent over a multiprocessing.Queue. Recovery behavior per failure location is below (all are current code paths, not a guarantee for every environment):

EventParent behaviorEffect on results
Top-level subprocess exception (returns an error result)Prints “批次错误” plus a traceback (with -v)Not counted as failed; the same batch stays in the pending list and is retried in the next round
Result-queue read timeout or exceptionPrints “无法获取子进程结果” and adds this batch's file count to failed_countThe batch is both counted as failed and, because it never entered completed_files, retried in the next round, risking double counting
A single image fails inside the subprocessCounted in failed_count, not added to completed_filesThe file stays pending and re-enters later batches; a reproducible failure can loop indefinitely
Subprocess does not exit within 30 secondsterminate(), then kill() if still alive after 5 secondsCompleted files survive; unfinished files re-enter the next round per the rules above
Memory limit hit, early returnReceives the success result normallyCompleted files survive; remaining files enter a new subprocess (batch count +1)
User presses Ctrl+CTerminates the current subprocess and exits with code 0Output already written survives; re-running without --overwrite skips existing files

What “checkpoint resume” actually means:

  • Within one run: completed_files guarantees that files already completed never re-enter a new batch after a memory-limit restart.
  • Across runs: the official top-level local has no usable --resume; cross-run recovery actually relies on the pre-filter that skips files whose output already exists when --overwrite is not set.
  • The worker also contains a torch/CUDA check block that runs every 5 images; in the current source it is a no-op (it does not free VRAM). Recorded as a static observation only.

Limitations

  • psutil is optional: when missing, both RSS and system-memory reads return 0, memory limits silently stop working, and only the image-count restart remains.
  • The three default layers must not be mixed: the official local defaults for --memory-limit/--memory-percent/--batch-per-restart are 0/0/0; the subprocess_manager.py function-signature constants are 0/80/50; the standalone parser in manga_translator/mode/local.py uses 8000/80/50. Only 0/0/0 from the official args.py belongs to the top-level local --help contract.
  • The help text of --format, --batch-size, and --attempts says “overrides the configuration file”, but in the subprocess branch only the GPU/ONNX overrides are written into cli_config; those three values never reach translate_with_subprocess. This is a source discrepancy, a code-path difference.
  • Subprocess mode runs exactly one subprocess at a time with no parallelism; cli.batch_concurrent does not participate in subprocess scheduling.
  • The memory limits target RAM (subprocess RSS / whole-machine memory), not GPU VRAM; VRAM exhaustion is covered by Models, GPU, and memory.
  • app.unload_models_after_translation (“Unload Models After Translation”) is a desktop-side unload switch for after a translation finishes, different from the runtime thresholds here.
  • The parent's result-queue timeout is “this batch's file count × 600 seconds”; with --batch-per-restart 0 and many files the wait can be extremely long.