diff --git a/etc/bashrc b/etc/bashrc
index 60030f8ce9cd5ced9f291672e201448c4c8492a1..9fc456394416b141804d7e5c3da579b3a05875e5 100644
--- a/etc/bashrc
+++ b/etc/bashrc
@@ -132,6 +132,11 @@ projectDir="$HOME/OpenFOAM/OpenFOAM-$WM_PROJECT_VERSION"
 # projectDir="@PROJECT_DIR@"
 : # Safety statement (if the user removed all fallback values)
 
+# [FOAM_MEMORY_POOL] - Optional memory management
+#                    - overrides the 'memory_pool' etc/controlDict entry
+# = "true | false | host [size=nn] [incr=nn]"
+#export FOAM_MEMORY_POOL="host"
+
 # [FOAM_SIGFPE] - Trap floating-point exceptions.
 #               - overrides the 'trapFpe' controlDict entry
 # = true | false
diff --git a/etc/controlDict b/etc/controlDict
index c3e7985415fd8f91f267cf87e185fd2a36a3ad57..2bece2b460609b3b23c38517e0a3da87568bf22d 100644
--- a/etc/controlDict
+++ b/etc/controlDict
@@ -221,6 +221,9 @@ OptimisationSwitches
     // Other
     // =====
 
+    // Optional memory management (sizing in MB)
+    // memory_pool     "host; size=1024; incr=5"
+
     // Trap floating point exception.
     // Can override with FOAM_SIGFPE env variable (true|false)
     trapFpe         1;
diff --git a/etc/cshrc b/etc/cshrc
index b36054eabd4975b995b4f0d52b547b2fb6fab26e..5e19865b00ba584ed5b4f6c6ff5fca73f18622ec 100644
--- a/etc/cshrc
+++ b/etc/cshrc
@@ -134,6 +134,11 @@ set projectDir=`lsof +p $$ |& sed -ne 's#^[^/]*##;\@/'"$projectName"'[^/]*/etc/c
 # Or optionally hard-coded (eg, with autoconfig)
 # set projectDir="@PROJECT_DIR@"
 
+# [FOAM_MEMORY_POOL] - Optional memory management
+#                    - overrides the 'memory_pool' etc/controlDict entry
+# = "true | false | host [size=nn] [incr=nn]"
+#setenv FOAM_MEMORY_POOL "host"
+
 # [FOAM_SIGFPE] - Trap floating-point exceptions.
 #               - overrides the 'trapFpe' controlDict entry
 # = true | false
diff --git a/src/OSspecific/MSwindows/Make/files b/src/OSspecific/MSwindows/Make/files
index 7c0823f3fcee6c7bada9f3bd48ebd1e686594e07..50c0c9bf652de1a5d2eb1ed70d11a49348e60f5f 100644
--- a/src/OSspecific/MSwindows/Make/files
+++ b/src/OSspecific/MSwindows/Make/files
@@ -3,6 +3,8 @@ MSwindows.C
 cpuInfo/cpuInfo.C
 memInfo/memInfo.C
 
+memory/MemoryPool.cxx
+
 signals/sigFpe.cxx
 signals/sigInt.cxx
 signals/sigQuit.cxx
diff --git a/src/OSspecific/MSwindows/memory/MemoryPool.cxx b/src/OSspecific/MSwindows/memory/MemoryPool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8dca735a50d658931f29148de7821e5cd2e2297e
--- /dev/null
+++ b/src/OSspecific/MSwindows/memory/MemoryPool.cxx
@@ -0,0 +1,83 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2025 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "MemoryPool.H"
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+// bool Foam::MemoryPool::create(const std::string& ctrl, bool verbose)
+// {
+//     return false;
+// }
+
+
+bool Foam::MemoryPool::create(bool verbose)
+{
+    // No banner information since it is currently never an option
+    return false;
+}
+
+
+void Foam::MemoryPool::destroy(bool verbose)
+{}
+
+
+bool Foam::MemoryPool::active() noexcept
+{
+    return false;
+}
+
+
+bool Foam::MemoryPool::suspend() noexcept
+{
+    return false;
+}
+
+
+void Foam::MemoryPool::resume() noexcept
+{}
+
+
+bool Foam::MemoryPool::is_pool(void* ptr)
+{
+    return false;
+}
+
+
+void* Foam::MemoryPool::try_allocate(std::size_t nbytes)
+{
+    return nullptr;
+}
+
+
+bool Foam::MemoryPool::try_deallocate(void* ptr)
+{
+    return (!ptr);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/OSspecific/POSIX/Allwmake b/src/OSspecific/POSIX/Allwmake
index 7bc223e001502f1431b0e73f4732b40d9d033da1..c02a48f9cfc3a6a44b889768cd4d49cf0b760fc8 100755
--- a/src/OSspecific/POSIX/Allwmake
+++ b/src/OSspecific/POSIX/Allwmake
@@ -2,6 +2,7 @@
 cd "${0%/*}" || exit                                # Run from this directory
 targetType=libo                                     # Preferred library type
 . ${WM_PROJECT_DIR:?}/wmake/scripts/AllwmakeParseArguments $*
+. ${WM_PROJECT_DIR:?}/wmake/scripts/have_umpire
 
 #------------------------------------------------------------------------------
 # Hack for MacOS (with Gcc).
@@ -59,6 +60,47 @@ then
     export COMP_FLAGS="-DFOAM_USE_INOTIFY"
 fi
 
+#------------------------------------------------------------------------------
+
+# Have -lumpire, but also -lcamp etc.
+# Also need to follow the link order
+get_umpire_libs()
+{
+    if [ -d "${UMPIRE_LIB_DIR}" ]
+    then
+        set -- $(
+            # Expected link order
+            for name in umpire fmt camp
+            do
+                [ -f "$UMPIRE_LIB_DIR/lib${name}.a" ] && echo "-l$name"
+            done
+        )
+        echo "$@"
+    else
+        echo
+    fi
+}
+
+
+if have_umpire
+then
+    libNames="$(get_umpire_libs)"
+
+    if [ -n "$libNames" ]
+    then
+        echo "    found umpire -- enabling memory pool interface" 1>&2
+        echo "    umpire libs: $libNames" 1>&2
+
+        COMP_FLAGS="$COMP_FLAGS -DFOAM_USE_UMPIRE -I${UMPIRE_INC_DIR}"
+        LINK_FLAGS="$LINK_FLAGS -L${UMPIRE_LIB_DIR} $libNames"
+        export COMP_FLAGS LINK_FLAGS
+    else
+        echo "    expecting umpire, but did not resolve the libraries" 1>&2
+    fi
+fi
+
+#------------------------------------------------------------------------------
+
 # Make object (non-shared by default)
 # Never want/need openmp, especially for static objects
 wmake -no-openmp $targetType
diff --git a/src/OSspecific/POSIX/Make/files b/src/OSspecific/POSIX/Make/files
index 29c8588445158e0820febf024a803f407fe03460..ed5d69dc73b037b6bdcce707961da2d7d6e80aaf 100644
--- a/src/OSspecific/POSIX/Make/files
+++ b/src/OSspecific/POSIX/Make/files
@@ -4,6 +4,8 @@ cpuInfo/cpuInfo.C
 cpuTime/cpuTimePosix.C
 memInfo/memInfo.C
 
+memory/MemoryPool.cxx
+
 signals/sigFpe.cxx
 signals/sigSegv.cxx
 signals/sigInt.cxx
diff --git a/src/OSspecific/POSIX/Make/options b/src/OSspecific/POSIX/Make/options
index 3f86d412a62b7c58d486f100cbde05dcc9de5827..2e18d513bdb61a9a7bf827570ef63deefb05e5d1 100644
--- a/src/OSspecific/POSIX/Make/options
+++ b/src/OSspecific/POSIX/Make/options
@@ -1 +1,4 @@
-EXE_INC = $(COMP_FLAGS)
+/* umpire uses old-style cast etc */
+EXE_INC = $(COMP_FLAGS) $(c++LESSWARN)
+
+LIBO_LIBS = $(LINK_FLAGS)
diff --git a/src/OSspecific/POSIX/memory/MemoryPool.cxx b/src/OSspecific/POSIX/memory/MemoryPool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..da65f06a7fc760530d6486730972be9b3e7b1685
--- /dev/null
+++ b/src/OSspecific/POSIX/memory/MemoryPool.cxx
@@ -0,0 +1,510 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2025 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "MemoryPool.H"
+#include "debug.H"
+#include "dictionary.H"
+#include "sigFpe.H"
+#include "OSspecific.H"  // For getEnv
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+#ifdef FOAM_USE_UMPIRE
+
+// #include <cerrno>
+#include <cinttypes>
+#include <tuple>
+
+#include "umpire/Allocator.hpp"
+#include "umpire/ResourceManager.hpp"
+#include "umpire/strategy/AlignedAllocator.hpp"
+#include "umpire/strategy/DynamicPoolList.hpp"
+
+static bool disabled_(false);
+static umpire::Allocator aligned_allocator;
+static umpire::Allocator pooled_allocator;
+static umpire::ResourceManager* manager_(nullptr);
+static umpire::ResourceManager* suspended_(nullptr);
+
+#endif
+
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
+
+#ifdef FOAM_USE_UMPIRE
+
+namespace
+{
+
+// Different supported allocation types
+enum class Types { undefined, none, host, device, managed };
+
+typedef std::tuple<Types, std::size_t, std::size_t> ctrlTuple;
+
+// Extract key=INT, the key includes the '='
+int getIntParameter(const std::string& key, const std::string& ctrl)
+{
+    int val(0);
+
+    const auto pos = ctrl.find(key);
+
+    if (pos == std::string::npos)
+    {
+        return val;
+    }
+
+    const char* buf = (ctrl.data() + pos + key.size());
+
+    char *endptr = nullptr;
+    errno = 0;
+    auto parsed = std::strtoimax(buf, &endptr, 10);
+
+    if (errno || endptr == buf)
+    {
+        // Some type of error OR no conversion
+    }
+    else
+    {
+        val = int(parsed);
+    }
+
+    return val;
+}
+
+
+ctrlTuple getControlValues(const std::string& ctrl)
+{
+    ctrlTuple result(Types::undefined, 0, 0);
+
+    bool checkParam = false;
+
+    // Also find things that look like Switch constants.
+    // Unfortunately need to do this manually since Switch::find()
+    // itself would not manage to parse something like "true; size=10"
+
+    if (ctrl.empty())
+    {
+        // Nothing => undefined
+    }
+    else if
+    (
+        std::string::npos != ctrl.find("false")     // ctrl.contains("false")
+     || std::string::npos != ctrl.find("off")       // ctrl.contains("off")
+     || std::string::npos != ctrl.find("no")        // ctrl.contains("no")
+     || std::string::npos != ctrl.find("none")      // ctrl.contains("none")
+    )
+    {
+        std::get<0>(result) = Types::none;
+    }
+    else if
+    (
+        std::string::npos != ctrl.find("true")      // ctrl.contains("true")
+     || std::string::npos != ctrl.find("on")        // ctrl.contains("on")
+     || std::string::npos != ctrl.find("yes")       // ctrl.contains("yes")
+
+     || std::string::npos != ctrl.find("host")      // ctrl.contains("host")
+     || std::string::npos != ctrl.find("system")    // ctrl.contains("system")
+    )
+    {
+        std::get<0>(result) = Types::host;
+        checkParam = true;
+    }
+
+    // These need more testing
+    else if
+    (
+        std::string::npos != ctrl.find("device")    // ctrl.contains("device")
+    )
+    {
+        std::get<0>(result) = Types::device;
+        checkParam = true;
+    }
+    else if
+    (
+        std::string::npos != ctrl.find("managed")   // ctrl.contains("managed")
+    )
+    {
+        std::get<0>(result) = Types::managed;
+        checkParam = true;
+    }
+
+    if (checkParam)
+    {
+        std::get<1>(result) = getIntParameter("size=", ctrl);
+        std::get<2>(result) = getIntParameter("incr=", ctrl);
+    }
+
+    return result;
+}
+
+
+bool create_from(const ctrlTuple& controls, bool verbose)
+{
+    using namespace Foam;
+
+    if (manager_ || suspended_)
+    {
+        // Already created
+        return true;
+    }
+
+    // Type, initial size, increment
+    auto [which, size, incr] = controls;
+
+    // std::cerr
+    //     << "which=" << int(which)
+    //     << ", size=" << int(size)
+    //     << ", incr=" << int(incr) << '\n';
+
+
+    constexpr size_t MegaByte(1024*1024);
+
+    switch (which)
+    {
+        case Types::undefined :
+        {
+            if (verbose)
+            {
+                Info<< "memory pool : unused" << nl;
+            }
+            break;
+        }
+
+        case Types::none :
+        {
+            if (verbose)
+            {
+                Info<< "memory pool : disabled" << nl;
+            }
+            break;
+        }
+
+        case Types::host :
+        {
+            // Default sizing parameters
+            if (!size) size = 1024;
+            if (!incr) incr = 5;
+
+            auto& rm = umpire::ResourceManager::getInstance();
+            manager_ = &rm;
+
+            aligned_allocator =
+                rm.makeAllocator<umpire::strategy::AlignedAllocator>
+                (
+                    "aligned_allocator",
+                    rm.getAllocator("HOST"),
+
+                    // alignment
+                    256
+                );
+
+            pooled_allocator =
+                rm.makeAllocator<umpire::strategy::DynamicPoolList>
+                (
+                    "openfoam_HOST_pool",
+                    aligned_allocator,
+
+                    // initial block allocation size
+                    (size*MegaByte),
+
+                    // incremental block allocation size
+                    (incr*MegaByte)
+                );
+
+            if (verbose)
+            {
+                Info<< "memory pool : host (size="
+                    << int(size) << "MB, incr="
+                    << int(incr) << "MB)\n";
+            }
+            break;
+        }
+
+        case Types::device :
+        {
+            auto& rm = umpire::ResourceManager::getInstance();
+            manager_ = &rm;
+
+            aligned_allocator = rm.getAllocator("DEVICE");
+
+            pooled_allocator =
+                rm.makeAllocator<umpire::strategy::DynamicPoolList>
+                (
+                    "openfoam_DEVICE_pool",
+                    aligned_allocator
+                );
+
+            if (verbose)
+            {
+                Info<< "memory pool : device" << nl;
+            }
+            break;
+        }
+
+        case Types::managed :
+        {
+            // Default sizing parameters
+            if (!size) size = 10*1024;
+            if (!incr) incr = 10;
+
+            auto& rm = umpire::ResourceManager::getInstance();
+            manager_ = &rm;
+
+            aligned_allocator = rm.getAllocator("UM");
+
+            pooled_allocator =
+                rm.makeAllocator<umpire::strategy::DynamicPoolList>
+                (
+                    "openfoam_UM_pool",
+                    aligned_allocator,
+
+                    // initial block allocation size
+                    (size*MegaByte),
+
+                    // incremental block allocation size
+                    (incr*MegaByte)
+                );
+
+            if (verbose)
+            {
+                Info<< "memory pool : managed (size="
+                    << int(size) << "MB, incr="
+                    << int(incr) << "MB)\n";
+            }
+            break;
+        }
+    }
+
+    return (which != Types::undefined && which != Types::none);
+}
+
+
+} // End anonymous namespace
+
+#endif  // FOAM_USE_UMPIRE
+
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+// bool Foam::MemoryPool::create(const std::string& ctrl, bool verbose)
+// {
+//     #ifdef FOAM_USE_UMPIRE
+//     if (manager_ || suspended_)
+//     {
+//         // Already created
+//         return true;
+//     }
+//
+//     auto controls = getControlValues(ctrl);
+//
+//     return create_from(controls, verbose);
+//     #else
+//     return false;
+//     #endif
+// }
+
+
+bool Foam::MemoryPool::create(bool verbose)
+{
+    #ifdef FOAM_USE_UMPIRE
+    if (disabled_)
+    {
+        // Disallowed
+        return false;
+    }
+    else if (manager_ || suspended_)
+    {
+        // Already created
+        return true;
+    }
+
+    // First check environment
+    auto controls = getControlValues(Foam::getEnv("FOAM_MEMORY_POOL"));
+
+    if (std::get<0>(controls) == Types::none)
+    {
+        // Disabled from environment - has highest priority
+        disabled_ = true;
+    }
+
+    // Currently no easy way to handle <system>/controlDict...
+
+    // Fallback from etc/controlDict
+    if (std::get<0>(controls) == Types::undefined)
+    {
+        // From central etc/controlDict
+        const auto& dict = Foam::debug::optimisationSwitches();
+
+        if (auto* eptr = dict.findStream("memory_pool", keyType::LITERAL))
+        {
+            const token& firstToken = eptr->front();
+
+            if (firstToken.isStringType())
+            {
+                controls = getControlValues(firstToken.stringToken());
+            }
+        }
+    }
+
+    return create_from(controls, verbose);
+    #else
+    if (verbose)
+    {
+        Info<< "memory pool : not available" << nl;
+    }
+    return false;
+    #endif
+}
+
+
+void Foam::MemoryPool::destroy(bool verbose)
+{
+    // Nothing currently needed but could add in something like this:
+
+    // if (manager_ || suspended_)
+    // {
+    //     pooled_allocator.release();
+    // }
+
+    // However, need to find the proper sequence within
+    // Foam::exit() or UPstream::exit() ...
+}
+
+
+bool Foam::MemoryPool::active() noexcept
+{
+    #ifdef FOAM_USE_UMPIRE
+    return bool(manager_);
+    #else
+    return false;
+    #endif
+}
+
+
+bool Foam::MemoryPool::suspend() noexcept
+{
+    #ifdef FOAM_USE_UMPIRE
+    bool status(suspended_);
+    if (manager_)  // <- and (!suspended_)
+    {
+        std::swap(manager_, suspended_);
+    }
+    return status;
+    #else
+    return false;
+    #endif
+}
+
+
+void Foam::MemoryPool::resume() noexcept
+{
+    #ifdef FOAM_USE_UMPIRE
+    if (suspended_)  // <- and (!manager_)
+    {
+        std::swap(manager_, suspended_);
+    }
+    #endif
+}
+
+
+bool Foam::MemoryPool::is_pool(void* ptr)
+{
+    #ifdef FOAM_USE_UMPIRE
+    if (ptr)
+    {
+        if (manager_)
+        {
+            return manager_->hasAllocator(ptr);
+        }
+        else if (suspended_)
+        {
+            return suspended_->hasAllocator(ptr);
+        }
+    }
+    #endif
+
+    return false;
+}
+
+
+void* Foam::MemoryPool::try_allocate(std::size_t nbytes)
+{
+    void* ptr = nullptr;
+
+    #ifdef FOAM_USE_UMPIRE
+    if (manager_)
+    {
+        ptr = pooled_allocator.allocate(nbytes);
+
+        // std::cerr<< "allocate(" << int(nbytes) << ")\n";
+
+        // Optionally fill with NaN (depends on current flags)
+        Foam::sigFpe::fillNan_if(ptr, nbytes);
+
+        if (!ptr)
+        {
+            // Pout<< "umpire failed to allocate memory\n";
+        }
+    }
+    #endif
+
+    return ptr;
+}
+
+
+bool Foam::MemoryPool::try_deallocate(void* ptr)
+{
+    #ifdef FOAM_USE_UMPIRE
+    if (ptr)
+    {
+        if (manager_)
+        {
+            if (manager_->hasAllocator(ptr))  // <- ie, is_pool()
+            {
+                // std::cerr<< "deallocate()\n";
+                manager_->deallocate(ptr);
+                return true;
+            }
+        }
+        else if (suspended_)
+        {
+            // Deallocate even if nominally suspended
+
+            if (suspended_->hasAllocator(ptr))  // <- ie, is_pool()
+            {
+                // std::cerr<< "deallocate()\n";
+                suspended_->deallocate(ptr);
+                return true;
+            }
+        }
+    }
+    #endif
+
+    return (!ptr);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/OpenFOAM/containers/Lists/policy/ListPolicy.H b/src/OpenFOAM/containers/Lists/policy/ListPolicy.H
index b7289be8fe076c14f3cbb9f6eec11ab9a1109327..be824287de92db3e29945ac87db7d8d8ab7c3125 100644
--- a/src/OpenFOAM/containers/Lists/policy/ListPolicy.H
+++ b/src/OpenFOAM/containers/Lists/policy/ListPolicy.H
@@ -34,6 +34,7 @@ Description
 #ifndef Foam_ListPolicy_H
 #define Foam_ListPolicy_H
 
+#include "MemoryPool.H"  // Also includes <cstdint>
 #include "contiguous.H"  // Also includes <type_traits>
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -103,6 +104,18 @@ template<> struct no_linebreak<wordRe> : std::true_type {};
 // - use_offload(n) :
 //   Lower threshold for switching to device offloading
 //
+//
+// Use of the memory-pool is controlled by the 'is_aligned_type()' test
+// and the minimum field size, controlled by the 'use_memory_pool()' test.
+//
+// If the memory-pool is not enabled or not required according to the two
+// above tests, the allocation falls back to either an aligned or unaligned
+// allocation.
+//
+// The decision about when to choose aligned vs unaligned allocation
+// is still a compile-time option. Made by direct edit of the
+// appropriate functions.
+//
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 //- Consider aligned allocation for the given type?
@@ -146,27 +159,104 @@ inline constexpr bool use_offload(IntType n) noexcept
 }
 
 
+//- Default alignment for larger fields
+inline constexpr std::align_val_t default_alignment() noexcept
+{
+    return std::align_val_t(256);
+}
+
+
+//- Allocate from memory pool (if active), or aligned, or normal
 template<class T, class IntType>
 inline T* allocate(IntType n)
 {
-    // Plain new
-    return new T[n];
+    if constexpr (ListPolicy::is_aligned_type<T>())
+    {
+        // Note: threshold for use_memory_pool() >= use_alignment()
+
+        if (ListPolicy::use_alignment(n))
+        {
+            if
+            (
+                void *pool_ptr
+                (
+                    // Consider memory pool for large amounts of data
+                    ListPolicy::use_memory_pool(n)
+                  ? Foam::MemoryPool::try_allocate(sizeof(T)*n)
+                  : nullptr
+                );
+                pool_ptr
+            )
+            {
+                // Placement new
+                return new (pool_ptr) T[n];
+            }
+            else
+            {
+                return new (ListPolicy::default_alignment()) T[n];
+            }
+        }
+        else
+        {
+            // Plain new
+            return new T[n];
+        }
+    }
+    else
+    {
+        // Plain new
+        return new T[n];
+    }
 }
 
 
+//- Deallocate from memory pool, or normal
 template<class T, class IntType>
 inline void deallocate(T* ptr)
 {
-    // Plain new
-    delete[] ptr;
+    if constexpr (ListPolicy::is_aligned_type<T>())
+    {
+        if (ptr && !Foam::MemoryPool::try_deallocate(ptr))
+        {
+            // Plain new
+            delete[] ptr;
+        }
+    }
+    else
+    {
+        // Plain new
+        delete[] ptr;
+    }
 }
 
 
+//- Deallocate from memory pool, or aligned, or normal
 template<class T, class IntType>
 inline void deallocate(T* ptr, [[maybe_unused]] IntType n)
 {
-    // Plain new
-    delete[] ptr;
+    if constexpr (ListPolicy::is_aligned_type<T>())
+    {
+        // Note: threshold for use_memory_pool() >= use_alignment()
+
+        if (ListPolicy::use_alignment(n))
+        {
+            if (ptr && !Foam::MemoryPool::try_deallocate(ptr))
+            {
+                // Alignment depends on the number of elements
+                ::operator delete[](ptr, ListPolicy::default_alignment());
+            }
+        }
+        else
+        {
+            // Plain new
+            delete[] ptr;
+        }
+    }
+    else
+    {
+        // Plain new
+        delete[] ptr;
+    }
 }
 
 
diff --git a/src/OpenFOAM/global/argList/argList.C b/src/OpenFOAM/global/argList/argList.C
index 0040be93d62a74fab1cc15a2f976dd39ae3b784a..3806e974caa18e1fbd6da562277fcb7d4ddd8a7e 100644
--- a/src/OpenFOAM/global/argList/argList.C
+++ b/src/OpenFOAM/global/argList/argList.C
@@ -37,6 +37,7 @@ License
 #include "IOobject.H"
 #include "dynamicCode.H"
 #include "simpleObjectRegistry.H"
+#include "MemoryPool.H"
 #include "sigFpe.H"
 #include "sigInt.H"
 #include "sigQuit.H"
@@ -2182,6 +2183,9 @@ void Foam::argList::parse
         sigQuit::set(bannerEnabled());
         sigSegv::set(bannerEnabled());
 
+        // Create memory pool (if any) after MPI has been setup
+        MemoryPool::create(bannerEnabled());
+
         if (UPstream::master() && bannerEnabled())
         {
             Info<< "fileModificationChecking : "
diff --git a/src/OpenFOAM/memory/pool/MemoryPool.H b/src/OpenFOAM/memory/pool/MemoryPool.H
new file mode 100644
index 0000000000000000000000000000000000000000..56879c3d42ff58404911e56b0ed17bb6fb339bd6
--- /dev/null
+++ b/src/OpenFOAM/memory/pool/MemoryPool.H
@@ -0,0 +1,116 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2025 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::MemoryPool
+
+Description
+    Optional memory management using a memory pool such as Umpire
+    (https://github.com/LLNL/Umpire).
+
+    When compiled with Umpire, its use can be controlled by the
+    \c FOAM_MEMORY_POOL environment variable, or the
+    \c memory_pool Optimisation switch (etc/controlDict).
+
+    It currently looks for any of the following entries, in this order:
+    - true - same as \em "host"
+    - false/none - disabled.
+    - \em "host" - uses host memory pool
+    - \em "system" - same as \em "host"
+    - \em "device" - uses device memory pool
+    - \em "managed" - uses managed host/device memory pool
+    .
+
+    The parameters "size=nn" and "incr=nn" (in MegaBytes) can be used
+    to specify alternatives to the default sizing.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef Foam_MemoryPool_H
+#define Foam_MemoryPool_H
+
+#include <cstdint>  // For size_t
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class MemoryPool Declaration
+\*---------------------------------------------------------------------------*/
+
+class MemoryPool
+{
+public:
+
+    // Constructors
+
+        //- Create a memory pool instance (if not already active).
+        //  Uses environment or etc/controlDict entry
+        static bool create(bool verbose = false);
+
+
+    // Destructor
+
+        //- Remove the memory pool instance (currently does nothing)
+        static void destroy(bool verbose = false);
+
+
+    // Member Functions
+
+        //- True if pool is active (ie, created and not suspended)
+        static bool active() noexcept;
+
+        //- Suspend use of memory pool (for allocation).
+        //  \return previous suspend status
+        static bool suspend() noexcept;
+
+        //- Resume use of memory pool (if previously active)
+        static void resume() noexcept;
+
+        //- Test if given pointer belongs to the pool
+        static bool is_pool(void *ptr);
+
+        //- Allocate from pool (if active).
+        //  \returns nullptr if the pool is not active
+        static void* try_allocate(std::size_t nbytes);
+
+        //- Deallocate a pointer managed by the pool
+        //  \returns True if a nullptr (no-op) or when the pointer was
+        //      managed by the pool.
+        static bool try_deallocate(void *ptr);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //