How to Load ncnn Model Parameters from Memory Using load_param_mem()
The ncnn::Net::load_param_mem() function wraps a resident memory buffer containing a text-based .param file in a DataReaderFromMemory instance to eliminate file-system I/O, while binary weight buffers loaded via load_model() must be 4-byte aligned to avoid undefined behavior on strict-alignment CPU architectures.
Tencent/ncnn provides load_param_mem() for embedded and mobile deployments where reading from disk is impractical or where models reside in encrypted or pre-loaded memory segments. This method, implemented in src/net.cpp, streams the ASCII parameter definition directly from the supplied pointer while delegating weight loading to separate memory-aware functions that enforce 32-bit alignment.
How load_param_mem() Works Internally
Wrapping Memory in DataReaderFromMemory
The implementation constructs a lightweight DataReaderFromMemory object that maintains a cursor into the supplied buffer. Located in src/net.cpp at lines 58-63, the method casts the const char* to an unsigned byte pointer and forwards it to the internal load_param(DataReader&) dispatcher:
const unsigned char* mem = reinterpret_cast<const unsigned char*>(_mem);
DataReaderFromMemory dr(mem);
return load_param(dr);
DataReaderFromMemory (defined in src/datareader.cpp) implements the abstract DataReader interface by advancing an internal pointer as scan() and read() operations consume data, eliminating temporary copies or buffering.
Parsing the Parameter Dictionary
Once wrapped, the buffer feeds into ParamDict::load_param(), found in src/paramdict.cpp (lines 63-84). This parser reads key-value pairs using sscanf patterns such as "%d=" to extract layer IDs, followed by type-specific scans for integers and floats. Because the data is treated as null-terminated text, the parser performs no speculative pointer casting, allowing the buffer to reside at any memory address regardless of alignment.
Language Bindings and C API
The functionality is exposed uniformly across language boundaries:
- C API:
ncnn_net_load_param_memory()insrc/c_api.cpp(line 1539) acts as a thin wrapper that unpacks the opaquencnn_net_thandle and forwards to the C++ method. - Python: The binding in
python/src/main.cppcasts the method pointer explicitly:
py::def("load_param_mem", (int (Net::*)(const char*)) &Net::load_param_mem).
Memory Alignment Requirements for ncnn Models
Understanding alignment constraints requires distinguishing between the text-based parameter metadata and the binary weight payloads.
Text Parameter Buffers Require No Alignment
The .param format contains only ASCII characters representing layer configurations. Since load_param_mem() processes this data through sscanf and character-level pointer arithmetic, the buffer can begin at any address. DataReaderFromMemory treats the input as a byte stream, making it safe to pass pointers from std::string::c_str(), static ROM arrays, or mmap'd regions without adjustment.
Binary Weight Buffers Require 4-Byte Alignment
Binary weight data loaded via load_model(const unsigned char* mem) demands stricter handling. According to docs/developer-guide/param-and-model-file-structure.md (lines 59-70), the .bin format stores weight blobs sequentially with 32-bit (4-byte) padding between sections to maintain alignment.
When you supply a memory buffer for weights, the framework interprets raw bytes as float, unsigned short, or uint8 arrays via pointer casting. On ARM architectures with strict alignment requirements, an unaligned float* access triggers a bus error or undefined behavior. To ensure safety:
- Allocate aligned storage using
fastMalloc_with_alignment(size, 4)fromsrc/allocator.cpp(lines 1322-1334). - Use POSIX aligned allocation:
posix_memalign(&ptr, 4, size)guarantees the buffer starts at a 4-byte boundary. - Preserve file mapping alignment: When using
mmaporCreateFileMapping, most operating systems return page-aligned addresses that satisfy the 4-byte requirement.
Practical Implementation Examples
Loading Parameters from a std::string
Use this pattern when you have embedded the .param content as a C++ string literal or read it into a std::string buffer:
#include "net.h"
#include <fstream>
#include <sstream>
int main()
{
ncnn::Net net;
// Read the param file into memory
std::ifstream ifs("model.param");
std::stringstream buffer;
buffer << ifs.rdbuf();
std::string param_text = buffer.str();
// Load directly from memory
int ret = net.load_param_mem(param_text.c_str());
if (ret != 0) {
fprintf(stderr, "load_param_mem failed\n");
return -1;
}
// Load weights from disk (or use load_model(mem) with aligned buffer)
net.load_model("model.bin");
return 0;
}
Key source: Net::load_param_mem in src/net.cpp (lines 58-63).
Loading via the C API
For C projects or FFI interoperability, use the ncnn_net_load_param_memory wrapper:
#include "c_api.h"
int main()
{
ncnn_net_t net = ncnn_net_create();
const char *param_buf = "7767517\n..."
"Input data 0 1 data 0=224 1=224 2=3\n"
"...";
int rc = ncnn_net_load_param_memory(net, param_buf);
if (rc != 0) {
fprintf(stderr, "C API load_param_memory failed: %d\n", rc);
ncnn_net_destroy(net);
return -1;
}
// Proceed to load binary weights...
ncnn_net_load_model(net, "model.bin");
ncnn_net_destroy(net);
return 0;
}
Key source: ncnn_net_load_param_memory in src/c_api.cpp (line 1539).
Loading Aligned Binary Weights from Memory
When bypassing file I/O for the .bin weights, explicitly enforce 4-byte alignment:
#include <cstdlib>
#include <fstream>
int load_aligned_weights(ncnn::Net& net, const char* filename)
{
// Determine file size
std::ifstream file(filename, std::ios::binary | std::ios::ate);
size_t size = file.tellg();
file.seekg(0, std::ios::beg);
// Allocate 4-byte aligned buffer
void* aligned_mem = nullptr;
if (posix_memalign(&aligned_mem, 4, size) != 0) {
return -1;
}
// Read data into aligned buffer
file.read(reinterpret_cast<char*>(aligned_mem), size);
file.close();
// Load model from aligned memory
int ret = net.load_model(reinterpret_cast<const unsigned char*>(aligned_mem));
// Cleanup (note: ncnn does not take ownership; free when net is destroyed)
free(aligned_mem);
return ret;
}
Key consideration: The pointer passed to load_model() must reference the start of a 4-byte aligned block to satisfy the expectations documented in docs/developer-guide/param-and-model-file-structure.md.
Summary
load_param_mem(const char* mem)enables zero-copy loading of text-based.paramdata by wrapping the pointer in aDataReaderFromMemoryand streaming it throughParamDict::load_param().- No alignment constraints apply to the parameter text buffer because parsing occurs via character-oriented
sscanfoperations. - 4-byte alignment is mandatory for binary weight buffers consumed by
load_model(const unsigned char* mem)to prevent undefined behavior when the framework casts raw bytes tofloatorunsigned shortpointers. - Allocation helpers such as
fastMalloc_with_alignment()(fromsrc/allocator.cpp) or POSIXposix_memalign()ensure compliance with the binary format's 32-bit padding requirements. - Cross-language support is available through the C API (
ncnn_net_load_param_memory) and Python bindings, both delegating to the core C++ implementation insrc/net.cpp.
Frequently Asked Questions
Does load_param_mem() copy the buffer or just reference it?
The function only references the buffer. The DataReaderFromMemory instance created on the stack in src/net.cpp stores the pointer and reads directly from it during the parsing phase. You must ensure the memory remains valid and unmodified for the duration of the load_param() call.
What happens if I pass a misaligned binary buffer to load_model()?
On architectures with strict alignment enforcement (such as 32-bit ARM), dereferencing an unaligned float* causes a bus error or SIGBUS crash. On x86_64, the CPU may handle unaligned access with significant performance penalties, but the behavior remains undefined according to the C++ standard.
Can I use load_param_mem() with encrypted model files?
Yes. Because load_param_mem() accepts a const char* to already-resident memory, you can decrypt a .param file into a heap or stack buffer and pass the plaintext pointer to the function. This avoids writing sensitive parameter definitions to temporary files.
How do I check if my memory buffer is properly aligned?
Verify that the address modulo 4 equals zero: (reinterpret_cast<uintptr_t>(ptr) % 4) == 0. When loading weights from external sources (such as network streams or compressed archives), copy the data into a buffer allocated with posix_memalign(&ptr, 4, size) or aligned_alloc(4, size) to guarantee compliance with ncnn's binary format requirements.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →