Jump to content

Optimizing Memory Usage on NVIDIA Jetson with Agent Skills

From RidgeRun Developer Wiki

Follow us on: YouTube Twitter LinkedIn Email Share this page

Share This Page

Saving RAM Memory on Jetson with Agent Skills


Optimizing Memory Usage on NVIDIA Jetson with Agent Skills

This guide showcases how NVIDIA agent skills can speed up a practical Jetson memory-optimization workflow. It combines manual measurement, host-side BSP customization, and target-side diagnosis to help developers identify unnecessary memory use, apply focused and reversible changes, and validate the effect on a representative workload.

The examples use an 8 GB Jetson Orin Nano Developer Kit. Disabling the desktop with $jetson-headless-mode increased idle available memory by 757 MiB. In an LLM-only test, it reduced RAM in use from 6235 MB to 5995 MB and swap use from 610 MB to 1 MB. Applying the BSP headless configuration additionally increased RAM visible to Linux by 68 MB, from 7546 MB to 7614 MB. The guide also compares the LLM workload with a concurrent GStreamer pipeline, showing why idle measurements must be supplemented with application-level testing.

This wiki can be used for:

  • establish a manual baseline with procrank, tegrastats, and NVIDIA memory-allocation data.
  • use agent skills to customize and flash a Jetson BSP, audit a running device, and apply reversible optimizations.
  • compare before-and-after results across reboots and workload conditions.

The measurements provide a concrete example of the workflow and its potential benefits and showcase how these tools can simplify applying and comparing memory optimizations.

Memory-optimization workflow—from baseline measurement to BSP or target-side changes and workload validation.

Memory optimization

Embedded systems have finite resources, while the demand for edge AI continues to increase. Two common approaches are: start with a minimal system and add only the required services and utilities (often with Yocto), or start with a full system for rapid prototyping and remove or optimize components as the product matures. This guide follows the second approach, which is common with JetPack: the initial installation is convenient for prototyping, but it usually has significant opportunities for memory optimization.

This can be done in several ways: disable unneeded systemd services, including journal- or graphical-UI-related services where appropriate, and optimize reserved memory regions when display or camera functionality is not required.

For inference pipelines, quantization is often the main memory-optimization option. Balance the required accuracy against throughput and latency when selecting and testing a quantization method. More advanced techniques, such as quantization-aware distillation (QAD), may also be appropriate.

Agents can be particularly useful for these tasks. For the NVIDIA ecosystem, NVIDIA provides agent skills that run on both the host—where they can apply BSP optimizations before flashing—and the target device, where they can help diagnose memory use interactively.

This guide demonstrates agent skills for BSP setup, BSP-side and target-side memory optimization, and memory-use diagnosis.

This guide uses an 8 GB Jetson Orin Nano Developer Kit.

Start with a manual memory baseline

Before changing the BSP or disabling services, it is good to inspect the system as it is. This gives you a baseline for identifying the largest memory consumers and for confirming that a later change genuinely improves the deployed workload.

procrank is a useful manual first step because it ranks processes by proportional set size (PSS). RSS includes shared pages in every process that maps them; PSS divides shared pages among those processes, making it more useful for estimating each process’s overall memory impact. USS estimates the memory likely to be freed when a process exits.

git clone https://github.com/csimmonds/procrank_linux.git
cd procrank_linux
make
sudo ./procrank

Example output:

  PID       Vss      Rss      Pss      Uss  cmdline
 2907  4196736K  290944K  217221K  172240K  /usr/bin/gnome-shell
 3521  3517264K  282092K  207075K  161936K  /usr/libexec/gnome-initial-setup
 3207  1234500K  179704K  146447K  138892K  /usr/bin/gnome-software
 9593   543952K   68148K   40925K   36436K  /usr/bin/python3
 1127  1996460K   40404K   39172K   39164K  /usr/lib/snapd/snapd
 3630   640068K   45424K   29710K   27240K  /usr/libexec/fwupd/fwupd
 1126  1839748K   29624K   28140K   28128K  /usr/lib/snapd/snap
 3193   843216K   59252K   23976K   14600K  /usr/libexec/evolution-data-server/evolution-alarm-notify
 7232   453568K   37356K   22130K   20232K  /usr/libexec/packagekitd
 2762   189292K   20056K   17760K   17500K  /usr/sbin/nvargus-daemon
 3026  1292816K   42028K   16138K    9176K  /usr/libexec/evolution-source-registry
 3522   739520K   27420K   14914K  12964K  /usr/libexec/tracker-miner-fs-3
 3523   641780K   38984K   14137K  10356K  /usr/libexec/xdg-desktop-portal-gnome
 3369   426628K   28344K   12527K  11616K  /usr/libexec/ibus-extension-gtk3
 3224   710612K   51860K   12263K   7272K  python3

Read the output from top to bottom: it is sorted by PSS by default. Use it to form a hypothesis—for example, that an unused desktop service is a significant consumer—then confirm that the service is not needed before disabling it.

For CUDA and multimedia pipelines, also inspect NVIDIA memory-client allocations when debugfs access is available:

sudo cat /sys/kernel/debug/nvmap/iovmm/clients

Additionally, tegrastats provides live continuous reads of memory usage on Jetson, which is critical for monitoring the overall memory, CPU, and GPU usage.

tegrastats

Example baseline output:

07-22-2026 23:25:57 RAM 1283/7546MB (lfb 3x4MB) SWAP 0/2048MB (cached 0MB) CPU [100%@1728,2%@1728,3%@1728,5%@1728,7%@729,0%@729] GR3D_FREQ 0% cpu@51.406C/51.406C soc2@49.187C/49.187C soc0@49.218C/49.218C gpu@50.406C/50.406C tj@51.406C/51.406C soc1@51.281C/51.281C VDD_IN 6570mW/6550mW/6570mW VDD_CPU_GPU_CV 1920mW/1900mW/1920mW VDD_SOC 1524mW/1524mW/1524mW

During testing is important to either keep a consistent power mode in the Jetson or keep it at max power for the best performance:

sudo nvpmodel -m 2

The next simplified diagram shows the two main places where memory was reclaimed for the following tests.

Simplified memory usage regions in NVIDIA Jetson

Agent skills for NVIDIA Jetpack BSP

To use these skills:

git clone https://github.com/NVIDIA-AI-IOT/jetson-bsp-skills.git

The repository includes a .claude directory. Codex and other agents can use the same configuration; for Codex, create a .agents symlink:

ln -s .claude .agents

Then start Codex:

codex

Use /skills to list available skills. You can request a specific skill or ask the model to set up the BSP workspace and environment, help build an image, or guide a board-flash workflow. For example:

help me setup the bsp customization workspace

or

$jetson-quick-setup

The model may require several base files by name. Find the matching files in JetPack Downloads or use the $jetson-download-bsp skill.

The skill can also guide board flashing. The agent may not be able to run sudo, so it can provide the commands for you to run. Expect it to ask whether you are using a development kit or a custom carrier board.

The agent creates target-specific configuration under /path/to/workspace/target-platform/; review and edit it as needed before building or flashing.

$jetson-flash-image

BSP host customization and optimization with agent skills (on the host)

This section uses host-side skills to optimize a Jetson BSP.

Clone the Jetson BSP skills repository from NVIDIA and navigate to the workspace:

git clone https://github.com/NVIDIA-AI-IOT/jetson-bsp-skills.git
cd jetson-bsp-skills/
./setup.sh /path/to/workspace
cd /path/to/workspace

The workspace must have the following structure. Create it manually or use the $jetson-quick-setup skill.

Image
└── Linux_for_Tegra
Source
└── bsp_sources

Use the $jetson-optimize-memory skill and select one or more of its three recipes:

- headless: reclaim DRAM by disabling display/DCE-related carveouts and display nodes
- no-camera: reclaim DRAM by disabling camera/RCE/VI/ISP-related carveouts and nodes
- swiotlb: reduce the SWIOTLB DMA bounce pool

Use headless only when the deployed product never needs a local display, and no-camera only when it never needs a camera. Reduce swiotlb carefully: peripherals that rely on DMA bounce buffers can fail or perform poorly if the pool is too small. Rebuild, flash, and validate the affected hardware after each change.

Once the model applies the related changes, you can use the $jetson-build-source and $jetson-promote-image before flashing.

Memory optimization with agent skills

This section uses skills directly on the Jetson.

Note: for this section we start with the base BSP flash.

First, make sure an agent is available on the Jetson. The following installation instructions use Codex as an example:

# Connect through SSH or log in locally.
sudo apt update
sudo apt install -y curl ca-certificates git
curl -fsSL https://chatgpt.com/codex/install.sh | sh
# When prompted to sign in, the device-code option is recommended.
# Validate
codex --version

Clone the skills repository from NVIDIA:

git clone https://github.com/NVIDIA-AI-IOT/jetson-device-skills.git
cd jetson-device-skills
# Select the appropriate target agent.
./install.sh --targets codex

After installation, start the agent and use these skills to identify optimization opportunities:

$jetson-diagnostic
$jetson-memory-audit

For example, $jetson-diagnostic produced the following output on an idle Jetson Orin Nano development kit:

• Jetson Orin Nano 8GB (7GB usable), L4T 39.2.0, currently in 25W mode.

  - RAM: 7.55GB total; 5.64GB available. Swap is enabled (2GB) but unused.
  - GPU: idle (0% GR3D); per-process GPU memory is unavailable because NvMap debugfs isn’t readable.
  - Temperatures: healthy—hottest sensor is 51.1°C.
  - Power draw: ~4.9W at sampling time.
  - Disk /: 5% used.
  - Largest RAM users: codex (~236MiB), gnome-shell (~202MiB), gnome-initial-setup (~190MiB), update-manager (~168MiB), gnome-software (~165MiB).
  - GUI is active (graphical.target, GDM running); Bluetooth, ModemManager, Avahi, kerneloops, and camera daemon are also active.

  Overall: the device is cool, lightly loaded, and has ample free memory.

and the $jetson-memory-audit produces:

• Memory audit baseline captured.

  - Total RAM: 7.37GiB
  - Available: 5.63GiB
  - Free: 3.63GiB
  - Cached: 1.99GiB
  - Swap: 2GiB configured, entirely unused
  - Current tegrastats: 1.64GB RAM in use; GPU idle

  Largest process memory consumers:

  - codex: ~226MiB PSS
  - gnome-shell: ~202MiB
  - gnome-initial-setup: ~190MiB
  - update-manager: ~168MiB
  - gnome-software: ~165MiB

  The desktop is active (graphical.target / GDM), and GPU-memory attribution is limited because NvMap debugfs isn’t readable. This is a healthy baseline with no memory pressure.

Several benchmarking skills are available, especially for LLM execution. This guide uses $jetson-llm-benchmark to benchmark an LLM model on the device:

This example uses Qwen3-8B-Q4_K_M.gguf, a 4-bit Q4_K_M GGUF quantization of the Qwen3-8B model. Qwen3-8B is a dense causal language model with 8.2 billion parameters; the 4-bit GGUF file is about 5.03 GB and is compatible with the llama.cpp runtime used by this benchmark.

GGUF is a model-file format designed for local inference runtimes such as llama.cpp. Quantization reduces the model storage and runtime-memory requirements compared with higher-precision weights, at the cost of some potential quality loss. Select the model size and quantization that meet your product’s accuracy, latency, and memory requirements; you can also ask the agent for a command to download a different model. See the official Qwen3-8B GGUF model card for model details and available quantizations.

mkdir -p ~/models/qwen3-8b
cd ~/models/qwen3-8b
wget -O Qwen3-8B-Q4_K_M.gguf \
  https://huggingface.co/Qwen/Qwen3-8B-GGUF/resolve/main/Qwen3-8B-Q4_K_M.gguf

Make sure Docker is available. If it is not, follow Installing the NVIDIA Container Toolkit.

In this case, the agent requested that the benchmark command be run manually because it requires sudo:

sudo bash /home/nvidia/jetson-device-skills/skills/jetson-llm-benchmark/scripts/bench_llama_cpp.sh \
    --model /home/nvidia/models/qwen3-8b/Qwen3-8B-Q4_K_M.gguf \
    --n-prompt 512 --n-gen 128 --n-gpu-layers 99

At MAXN, the following results were obtained:

{
  "skill": "jetson-llm-benchmark",
  "runtime": "llama.cpp",
  "model": "Qwen3-8B-Q4_K_M.gguf",
  "sku": "orin-nano",
  "generation": "orin",
  "product_line": "orin-nano",
  "variant": "orin-nano-8gb",
  "l4t": "39.2.0",
  "container": "ghcr.io/nvidia-ai-iot/llama_cpp:latest-jetson-orin",
  "config": {
    "n_prompt": 512,
    "n_gen": 128,
    "n_gpu_layers": 99
  },
  "metrics": {
    "ttft_ms_p50": 1653.06,
    "itl_ms_p50": 90.34,
    "tpot_ms_p50": 90.34,
    "throughput_tok_s": 11.07
  },
  "warnings": [
    "llama-bench stderr: ggml_cuda_init: found 1 CUDA devices (Total VRAM: 7546 MiB):"
  ]
}

Running this benchmark provides the following tegrastats numbers:

RAM 6235/7546MB (lfb 1x1MB) SWAP 610/2048MB (cached 154MB) CPU [0%@729,1%@729,2%@729,1%@729,0%@729,0%@729] GR3D_FREQ 100%

Additionally, running a simple pipeline in parallel can take up more memory; note that this platform lacks a hw encoder:

gst-launch-1.0 -e     videotestsrc is-live=true num-buffers=3600 pattern=ball !     'video/x-raw,width=2560,height=1440,framerate=30/1' !     x264enc tune=zerolatency speed-preset=ultrafast bitrate=4000 !     h264parse !     fpsdisplaysink video-sink=fakesink sync=false text-overlay=false

With the pipeline running simultaneously, the benchmark and tegrastats results were:

{
  "skill": "jetson-llm-benchmark",
  "runtime": "llama.cpp",
  "model": "Qwen3-8B-Q4_K_M.gguf",
  "sku": "orin-nano",
  "generation": "orin",
  "product_line": "orin-nano",
  "variant": "orin-nano-8gb",
  "l4t": "39.2.0",
  "container": "ghcr.io/nvidia-ai-iot/llama_cpp:latest-jetson-orin",
  "config": {
    "n_prompt": 512,
    "n_gen": 128,
    "n_gpu_layers": 99
  },
  "metrics": {
    "ttft_ms_p50": 1537.35,
    "itl_ms_p50": 103.36,
    "tpot_ms_p50": 103.36,
    "throughput_tok_s": 9.67
  },
  "warnings": [
    "llama-bench stderr: ggml_cuda_init: found 1 CUDA devices (Total VRAM: 7546 MiB):"
  ]
}

While tegrastats shows:

RAM 6376/7546MB (lfb 1x1MB) SWAP 698/2048MB (cached 124MB) CPU [33%@1651,25%@1651,33%@1651,41%@1651,29%@729,30%@729] GR3D_FREQ 99%

As one gets familiar with the skills, it is possible to review the available scripts directly; for example, we can read the scripts available in the skill repository which might be used by the agent when requested:

nvidia@tegra-ubuntu:~/jetson-device-skills$ find . -iname "*sh"
./install.sh
./skills/jetson-diagnostic/scripts/detect_jetson.sh
./skills/jetson-diagnostic/scripts/common.sh
./skills/jetson-diagnostic/scripts/mem_summary.sh
./skills/jetson-diagnostic/scripts/runtime_probes.sh
./skills/jetson-diagnostic/scripts/snapshot.sh
./skills/jetson-memory-audit/scripts/audit.sh
./skills/jetson-memory-audit/scripts/drop_caches.sh
./skills/jetson-headless-mode/scripts/plan.sh
./skills/jetson-headless-mode/scripts/apply.sh
./skills/jetson-package/scripts/artifact_hints.sh
./skills/jetson-llm-benchmark/scripts/bench_llama_cpp.sh
./skills/jetson-llm-benchmark/scripts/bench_ollama.sh
./skills/jetson-llm-benchmark/scripts/bench_vllm.sh

While the agent can run these, for repetitive cases it can be useful to have a manual command at hand; also, since the agent session application takes up some memory, it can help provide more accurate real-world use results. Although some of them might require multiple arguments or further considerations, they can also be used in separate scripts or updated for specific cases.

Furthermore, by applying the $jetson-headless-mode skill, we can apply, validate, and compare a considerable memory usage reduction in a very simple manner; for this case, we repeat and compare the same workload after freeing up this memory.

The agent skill can also validate reclaimed memory. Context can persist across reboots, allowing direct before-and-after comparisons, making it surprisingly easy to compare and test different scenarios:

• Headless mode is applied and working.

  - Boot target: multi-user.target
  - GDM/display manager: inactive
  - Bluetooth, ModemManager, kerneloops, and Avahi: inactive and disabled
  - Docker and camera support remain active

  Compared with the pre-change audit:

  - Available RAM: 5.82GiB → 6.56GiB
    +757MiB available

  - Swap use: ~377MiB → 0
  - Tegrastats RAM use: 1.58GB → 664MB

  This is a strong, capacity/stability result. The next useful test is the Qwen3 8B benchmark with the same parameters used before headless mode.

This kind of workflow is great for rapid prototyping; however, the final decision must be based on a benchmark representative of your application. Additionally, the agent can undo the optimizations done if you need to restore something or do further baseline comparisons.

Repeated $jetson-llm-benchmark LLM benchmark alone after using headless skill:

{
  "skill": "jetson-llm-benchmark",
  "runtime": "llama.cpp",
  "model": "Qwen3-8B-Q4_K_M.gguf",
  "sku": "orin-nano",
  "generation": "orin",
  "product_line": "orin-nano",
  "variant": "orin-nano-8gb",
  "l4t": "39.2.0",
  "container": "ghcr.io/nvidia-ai-iot/llama_cpp:latest-jetson-orin",
  "config": {
    "n_prompt": 512,
    "n_gen": 128,
    "n_gpu_layers": 99
  },
  "metrics": {
    "ttft_ms_p50": 1625.85,
    "itl_ms_p50": 89.81,
    "tpot_ms_p50": 89.81,
    "throughput_tok_s": 11.13
  },
  "warnings": [
    "llama-bench stderr: ggml_cuda_init: found 1 CUDA devices (Total VRAM: 7546 MiB):"
  ]
}

tegrastats output:

RAM 5995/7546MB (lfb 1x512kB) SWAP 1/2048MB (cached 0MB) CPU [2%@1036,0%@1036,0%@1036,0%@1036,0%@729,0%@729] GR3D_FREQ 99%

End-to-end headless test: BSP and target

This final experiment combines the earlier host-side headless BSP recipe with $jetson-headless-mode on the flashed board.

The board was flashed with the BSP image produced by $jetson-optimize-memory using the headless recipe, then target-side headless mode was applied before repeating the same LLM benchmark.

{
  "skill": "jetson-llm-benchmark",
  "runtime": "llama.cpp",
  "model": "Qwen3-8B-Q4_K_M.gguf",
  "sku": "orin-nano",
  "generation": "orin",
  "product_line": "orin-nano",
  "variant": "orin-nano-8gb",
  "l4t": "39.2.0",
  "container": "ghcr.io/nvidia-ai-iot/llama_cpp:latest-jetson-orin",
  "config": {
    "n_prompt": 512,
    "n_gen": 128,
    "n_gpu_layers": 99
  },
  "metrics": {
    "ttft_ms_p50": 1547.26,
    "itl_ms_p50": 90.52,
    "tpot_ms_p50": 90.52,
    "throughput_tok_s": 11.05
  },
  "warnings": [
    "llama-bench stderr: ggml_cuda_init: found 1 CUDA devices (Total VRAM: 7614 MiB):"
  ]
}
RAM 5982/7614MB (lfb 2x2MB) SWAP 1/2048MB (cached 0MB) CPU [0%@729,0%@729,1%@729,0%@729,0%@729,0%@729] GR3D_FREQ 99%


tegrastats memory summary

The table compares the four recorded tegrastats snapshots. Each value is a point-in-time reading, so use it to compare the test conditions rather than as a peak-memory measurement.

Test condition RAM in use Total RAM Swap in use Swap total
Before headless mode: LLM benchmark alone 6235 MB 7546 MB 610 MB 2048 MB
Before headless mode: LLM benchmark + GStreamer pipeline 6376 MB 7546 MB 698 MB 2048 MB
After target-side headless mode: LLM benchmark alone 5995 MB 7546 MB 1 MB 2048 MB
After BSP + target-side headless mode: LLM benchmark alone 5982 MB 7614 MB 1 MB 2048 MB

After target-side headless mode, the LLM-only run used 240 MB less RAM and 609 MB less swap than the corresponding pre-headless run. The lower swap use is the clearest result. The combined BSP and target-side configuration reported 7614 MB total RAM, 68 MB more than the target-only result, while using 5982 MB RAM and 1 MB swap during the LLM test.


Agent-reported idle comparison

The agent diagnostic comparison was collected while the system was idle, so it measures a different condition from the workload table above. It reported the following changes after headless mode was applied:

Metric Before headless mode After headless mode Reported difference
Available RAM 5.82 GiB 6.56 GiB +757 MiB
Swap in use about 377 MiB 0 MiB about -377 MiB
tegrastats RAM in use 1.58 GB 664 MB about -916 MB

These idle measurements show substantial reclaimed system memory. However, it is also important to compare results under a workload.

The reported diagnostic while idle has a much larger reduction in tegrastats RAM use (about 916 MB), while the LLM workload showed only 240 MB less RAM in use. This difference is worth noting: the benchmark allocates memory differently. Swap activity may also affect how memory pressure appears; the recorded post-headless workload used substantially less swap, though.

Conclusions and practical takeaways

Agent skills make it much easier to explore, apply, and compare memory optimizations across the full Jetson workflow—from BSP customization on the host to diagnosis and benchmarking on the target device.

  • Start with a baseline. Use procrank, tegrastats, and the memory-audit skills to identify the largest consumers before changing the system.
  • Use skills to accelerate iteration. They can guide BSP setup, apply targeted recipes such as headless mode, preserve context across reboots, and summarize before-and-after results.
  • Measure the actual workload. Idle-memory savings are valuable, but the release decision should be based on RAM, swap, latency, throughput, power, and thermal behavior while the real application is running.
  • Keep changes reversible. Record the configuration, validate each required peripheral after a change, and retain a rollback path so that a display, camera, or service can be restored if needed.
  • Treat the measurements as platform-specific. The results in this guide apply to the tested 8 GB Jetson Orin Nano Developer Kit and should be reproduced on the target hardware, JetPack release, and carrier-board configuration.
  • Keep context files across reflashes. When using an agent on the Jetson, you can ask it to generate context documents and store them on the host before reflashing. This makes it easier to compare results across test sequences.

References



For direct inquiries, please refer to the contact information available on our Contact page. Alternatively, you may complete and submit the form provided at the same link. We will respond to your request at our earliest opportunity.


Links to RidgeRun Resources and RidgeRun Artificial Intelligence Solutions can be found in the footer below.


Cookies help us deliver our services. By using our services, you agree to our use of cookies.