Optimizing Memory Usage on NVIDIA 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
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.

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
- Maximizing Memory Efficiency with Agent Skills to Run Bigger Models on NVIDIA Jetson
- NVIDIA Container Toolkit Installation Guide
- NVIDIA Jetson Device Skills repository
- NVIDIA Jetson BSP Skills repository
- Codex CLI: Getting started
- Qwen3-8B GGUF model card
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.