Strata is a portable C++20 memory placement and allocation library with first-class ESP32 internal-RAM and PSRAM support.
It gives applications and libraries one vocabulary for allocation intent while platform-specific backends own the underlying memory mechanics. Core allocation APIs remain standard-C++ compatible, while optional PMR, FreeRTOS, and ArduinoJson integrations add specialized capabilities without leaking them into the core contract.
- Explicit placement — request default, internal, preferred-external, or required-external memory.
- Shared memory policy — embed
Strata::MemoryPolicyin ZekStack library configs for consistent allocation and task-stack defaults. - Portable vocabulary — application code describes memory intent instead of ESP-IDF heap flags.
- Strict capability requirements — DMA and executable requirements never silently degrade.
- Typed ownership — raw allocation, typed construction, unique ownership, shared ownership, and move-only buffers use the same placement model.
- STL integration — placement-aware allocators and container helpers preserve allocation intent.
- PMR integration — use the same placement policies through standard polymorphic allocators and nested PMR containers.
- Runtime diagnostics — inspect actual memory regions, heap statistics, and current/peak region usage.
- Optional advanced diagnostics — opt into allocation/failure/fallback counters without a global allocation registry.
- Optional FreeRTOS memory primitives — explicitly place task stacks and queue item storage, and own static mutex/binary-semaphore control blocks, while keeping FreeRTOS out of the core headers.
- Optional ArduinoJson allocation — route ArduinoJson 7 document memory through the same Strata placement policies.
- Standalone core — Strata does not depend on other ZekStack libraries.
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/strata.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11ArduinoJson users should add ArduinoJson separately because it remains an optional integration:
lib_deps =
https://github.com/ZekStack/strata.git
bblanchon/ArduinoJson@^7.4.3Strata is not published to Arduino Library Manager yet.
Install it by downloading the repository ZIP or cloning it into the Arduino libraries directory:
Arduino/libraries/Strata
#include <Arduino.h>
#include <Strata.h>
void setup() {
Serial.begin(115200);
void *bulk = Strata::allocate(4096, Strata::Placement::PreferExternal);
if (bulk == nullptr) {
Serial.println("allocation failed");
return;
}
Serial.printf("region=%u\n", static_cast<unsigned>(Strata::regionOf(bulk)));
Strata::free(bulk);
}
void loop() {
delay(1000);
}Owned buffers and STL helpers use the same placement policy:
Strata::Buffer buffer(4096, Strata::Placement::PreferExternal);
auto values = Strata::makeVector<int>(Strata::Placement::PreferExternal);
values.push_back(42);Reusable library configs can expose the shared policy type directly:
struct SomeLibConfig {
Strata::MemoryPolicy memory{};
};
SomeLibConfig config;
config.memory.allocation = Strata::Placement::PreferExternal;
config.memory.taskStack = Strata::Placement::Internal;Important
PreferExternal may fall back to internal memory. RequireExternal never does. Capability requirements such as DMA or executable memory remain mandatory during fallback.
Placementdescribes requested policy;Regiondescribes where memory actually resides.MemoryPolicyis local configuration vocabulary, not a global Strata setting. Hard safety requirements may tighten its defaults.Placement::Defaultmeans backend-default allocation and must not be used as an inheritance sentinel.- Invalid or corrupted
Placementenum values are rejected by allocation/support APIs instead of being interpreted as another policy. - Generic builds support normal process-heap allocation but deliberately report external-memory and embedded hardware capabilities as unsupported. The generic backend is validated with GCC/Clang-compatible C++20 toolchains; native MSVC is not supported.
- Raw allocation, typed ownership, and
Bufferreport allocation failure without requiring exceptions. Strata::Allocator<T>follows standard allocator expectations and throwsstd::bad_allocwhen exceptions are enabled.- The optional PMR adapter requires standard-library
<memory_resource>support and exceptions to preservestd::pmr::memory_resourcefailure semantics. - External RAM is not automatically safe for DMA, ISR use, or cache-disabled flash windows.
- FreeRTOS task, queue, mutex, and binary-semaphore integrations are opt-in and require static allocation support. The task wrapper also requires
INCLUDE_vTaskDelete == 1andINCLUDE_uxTaskGetStackHighWaterMark == 1; the mutex wrapper requires mutex and recursive-mutex support. - A
Strata::FreeRTOS::Taskowner must be destroyed/reset from a different task context than the task it owns; managed tasks must not self-delete. - Tasks that can execute while flash/cache is disabled should keep their stacks in internal memory.
- ISR-accessible Strata queues require internal item storage; external queue storage is task-only.
- Strata mutex and binary-semaphore control blocks are always internal and use FreeRTOS static creation APIs.
BinarySemaphore::create()produces an initially-empty semaphore; task and ISR give/take operations report success explicitly.- ArduinoJson integration is opt-in, targets ArduinoJson 7, and requires the Strata allocator object to outlive the
JsonDocumentusing it. - Advanced allocation counters are disabled by default; enable them build-wide with
STRATA_ENABLE_ADVANCED_DIAGNOSTICS=1.
| Example | Description |
|---|---|
Basic |
Minimal allocation, region inspection, and cleanup. |
Placement |
Placement and region terminology. |
Allocation |
Raw allocation and explicit requests. |
Diagnostics |
Support queries and heap statistics. |
TypedOwnership |
Typed construction and ownership helpers. |
STL |
Placement-aware standard-library containers. |
Buffer |
Move-only owned byte buffers and resize behavior. |
Capabilities |
DMA/executable capability requirements. |
FreeRTOSTask |
Optional placed FreeRTOS task stacks and diagnostics. |
FreeRTOSQueue |
Optional typed FreeRTOS queues with placed item storage. |
FreeRTOSMutex |
Optional static mutex and recursive-mutex ownership. |
FreeRTOSBinarySemaphore |
Optional static binary semaphore signaling with task and ISR APIs. |
ArduinoJson |
Optional ArduinoJson 7 document allocation through Strata placement. |
Start with:
examples/Basic
| Document | Description |
|---|---|
docs/getting-started.md |
Installation, first allocation, and placement choices. |
docs/placement.md |
Stable placement, region, fallback, reallocation, and safety semantics. |
docs/memory-policy.md |
Shared ZekStack library configuration contract for allocations and task stacks. |
docs/migration.md |
Recipes for migrating raw allocation, library policies, containers, tasks, queues, mutexes, and adapters. |
docs/configuration.md |
Build requirements, backend selection, PSRAM, diagnostics, exceptions, and optional integrations. |
docs/api.md |
Public API overview and include boundaries. |
docs/examples.md |
Guide to the included sketches. |
docs/troubleshooting.md |
Common allocation, PSRAM, capability, and integration issues. |
docs/architecture.md |
Architectural boundaries, stable vocabulary, platform mapping, and failure contracts. |
docs/diagnostics.md |
Region/heap introspection plus optional allocation/failure/fallback counters. |
docs/typed-ownership.md |
Typed raw storage, object lifetime, and unique ownership. |
docs/stl.md |
Stateful allocator semantics and STL helpers. |
docs/pmr.md |
Optional placement-aware std::pmr::memory_resource integration. |
docs/buffer.md |
Owned byte buffers and resize semantics. |
docs/capabilities.md |
Required DMA/executable constraints and safety boundaries. |
docs/freertos-tasks.md |
Optional task-stack placement and static task creation. |
docs/freertos-queues.md |
Optional typed queue storage placement and ISR safety. |
docs/freertos-mutexes.md |
Optional internal static mutex and recursive-mutex ownership. |
docs/freertos-binary-semaphores.md |
Optional internal static binary semaphore ownership and ISR signaling. |
docs/arduinojson.md |
Optional ArduinoJson 7 custom allocator integration. |
docs/roadmap.md |
Completed v0.1.0 roadmap and post-release planning boundary. |
docs/ecosystem-adoption.md |
Planned adoption across ZekStack and Core. |
docs/releasing.md |
Version/tag requirements and the validated GitHub release flow. |
void *raw = Strata::allocate(4096, Strata::Placement::PreferExternal);
void *dma = Strata::allocate(Strata::AllocationRequest{
.sizeBytes = 1024,
.placement = Strata::Placement::Internal,
.alignment = 32,
.capabilities = Strata::Capability::Dma,
});
Strata::MemoryPolicy policy{
.allocation = Strata::Placement::PreferExternal,
.taskStack = Strata::Placement::Internal,
};
Strata::Buffer buffer(4096, Strata::Placement::PreferExternal);
auto object = Strata::makeUnique<MyType>(Strata::Placement::PreferExternal, constructorArg);
auto values = Strata::makeVector<int>(Strata::Placement::PreferExternal);
auto stats = Strata::memoryStats(Strata::Region::Internal);
Strata::free(raw);
Strata::free(dma);With advanced diagnostics enabled at build time:
auto total = Strata::allocationDiagnostics();
auto preferred = Strata::allocationDiagnostics(Strata::Placement::PreferExternal);
Serial.printf("failures=%u fallbacks=%u\n",
static_cast<unsigned>(total.failures),
static_cast<unsigned>(preferred.preferredExternalFallbacks));Optional PMR integration:
#include <strata/pmr/MemoryResource.h>
Strata::MemoryResource resource{Strata::Placement::PreferExternal};
std::pmr::vector<std::pmr::string> values{&resource};
values.emplace_back("Strata");Optional ArduinoJson integration:
#include <ArduinoJson.h>
#include <strata/arduinojson/Allocator.h>
Strata::ArduinoJson::Allocator allocator{Strata::Placement::PreferExternal};
ArduinoJson::JsonDocument document{&allocator};
document["library"] = "Strata";Optional FreeRTOS integrations:
#include <strata/freertos/Task.h>
#include <strata/freertos/Queue.h>
#include <strata/freertos/Mutex.h>
#include <strata/freertos/BinarySemaphore.h>
Strata::FreeRTOS::Task task = Strata::FreeRTOS::Task::create(worker, nullptr, {
.name = "worker",
.stackBytes = 4096,
.stackPlacement = Strata::Placement::PreferExternal,
.priority = 1,
.affinity = Strata::FreeRTOS::NoAffinity,
});
auto queue = Strata::FreeRTOS::Queue<Event>::create({
.length = 16,
.storagePlacement = Strata::Placement::PreferExternal,
.usage = Strata::FreeRTOS::QueueUsage::TaskOnly,
});
auto mutex = Strata::FreeRTOS::Mutex::create();
auto recursiveMutex = Strata::FreeRTOS::RecursiveMutex::create();
auto ready = Strata::FreeRTOS::BinarySemaphore::create();
ready.give();| Item | Support |
|---|---|
| Language | C++20 |
| Core API | Standard C++ |
| ESP32 backend | Arduino ESP32 / ESP-IDF-compatible build environment |
| Generic backend | GCC/Clang-compatible C++20 process heap; native MSVC is not supported |
| External memory | ESP32 PSRAM through ESP-IDF heap capabilities |
| Core dependencies | none |
| Optional PMR integration | Standard-library <memory_resource> with exceptions enabled |
| Optional FreeRTOS integration | FreeRTOS with static allocation; task deletion/high-water-mark APIs for tasks; mutex and recursive-mutex support for mutex wrappers; binary semaphore task/ISR support |
| Optional ArduinoJson integration | ArduinoJson 7; CI compatibility target 7.4.3 |
| Advanced diagnostics | Optional compile-time counters; disabled by default |
| Exceptions | Not required by core APIs; STL/PMR standard allocator surfaces follow standard semantics |
| Status | v0.1.2 binary semaphore compatibility release |
MIT — see LICENSE.md.
Part of the ZekStack library stack. v0.1.2 adds static FreeRTOS binary semaphore ownership while preserving the shared memory-policy and placement contracts established for Worker and subsequent ZekStack libraries.