Pool LogMessageData instances in a 16-slot lock-free ObjectPool.

Every active `LOG(...)` statement previously allocated and deallocated a ~30.5 KB `LogMessageData` buffer from the global heap (`std::make_unique<LogMessageData>`) and constructed and destroyed its `std::ostream` state whenever `OstreamView` was used.

Introduce `absl::log_internal::ObjectPool<T, kCapacity>` in `log/internal/object_pool.h`, a cacheline-aligned, `ABSL_CONST_INIT`-compatible, trivially destructible lock-free object pool probed from a `thread_local` slot hint (or `GetCachedTID() % kCapacity` when `ABSL_HAVE_THREAD_LOCAL` is unavailable), falling back to `std::make_unique<T>` and `delete` when all `kCapacity` slots are concurrently in use. Use `ObjectPool<LogMessageData, 16>` (`LogMessageData::pool`) and `LogMessageData::Reset` to reuse `LogMessageData` instances across `LogMessage` lifetimes without touching the two 15 KB buffers (`encoded_buf` and `string_buf`), and track per-message `manipulated_used` state so a pooled `std::ostream` is constructed at most once per slot and reset (`clear`, `flags`, `precision`, `width`, `fill`) once per `LogMessage` when `OstreamView` is entered.

PiperOrigin-RevId: 1004864407
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index 5b24d67..adf98dc 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -195,6 +195,7 @@
   "log/internal/nullguard.cc"
   "log/internal/nullguard.h"
   "log/internal/nullstream.h"
+  "log/internal/object_pool.h"
   "log/internal/proto.cc"
   "log/internal/proto.h"
   "log/internal/strip.h"
diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt
index 1da38e4..58cad49 100644
--- a/absl/log/CMakeLists.txt
+++ b/absl/log/CMakeLists.txt
@@ -206,6 +206,7 @@
     absl::log_internal_globals
     absl::log_internal_log_sink_set
     absl::log_internal_nullguard
+    absl::log_internal_object_pool
     absl::log_internal_proto
     absl::log_internal_structured_proto
     absl::log_severity
@@ -286,6 +287,22 @@
 
 absl_cc_library(
   NAME
+    log_internal_object_pool
+  HDRS
+    "internal/object_pool.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::base
+    absl::config
+    absl::core_headers
+    absl::nullability
+)
+
+absl_cc_library(
+  NAME
     log_internal_strip
   HDRS
     "internal/strip.h"
@@ -1239,3 +1256,20 @@
     absl::strings
     GTest::gmock_main
 )
+
+absl_cc_test(
+  NAME
+    internal_object_pool_test
+  SRCS
+    "internal/object_pool_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+    absl::core_headers
+    absl::log_internal_object_pool
+    GTest::gmock_main
+)
+
diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel
index 42114ed..e1a64ba 100644
--- a/absl/log/internal/BUILD.bazel
+++ b/absl/log/internal/BUILD.bazel
@@ -201,6 +201,7 @@
         ":globals",
         ":log_sink_set",
         ":nullguard",
+        ":object_pool",
         ":proto",
         ":structured_proto",
         "//absl/base",
@@ -293,6 +294,33 @@
 )
 
 cc_library(
+    name = "object_pool",
+    hdrs = ["object_pool.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        "//absl/base",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "//absl/base:nullability",
+    ],
+)
+
+cc_test(
+    name = "object_pool_test",
+    srcs = ["object_pool_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":object_pool",
+        "//absl/base:config",
+        "//absl/base:core_headers",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
+
+cc_library(
     name = "strip",
     hdrs = ["strip.h"],
     copts = ABSL_DEFAULT_COPTS,
diff --git a/absl/log/internal/log_message.cc b/absl/log/internal/log_message.cc
index e56ef25..6e6e515 100644
--- a/absl/log/internal/log_message.cc
+++ b/absl/log/internal/log_message.cc
@@ -25,9 +25,11 @@
 #include <atomic>
 #include <ios>
 #include <memory>
+#include <optional>
 #include <ostream>
 #include <string>
 #include <string_view>
+#include <utility>
 
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
@@ -44,6 +46,7 @@
 #include "absl/log/internal/log_format.h"
 #include "absl/log/internal/log_sink_set.h"
 #include "absl/log/internal/nullguard.h"
+#include "absl/log/internal/object_pool.h"
 #include "absl/log/internal/proto.h"
 #include "absl/log/internal/structured_proto.h"
 #include "absl/log/log_entry.h"
@@ -148,11 +151,19 @@
 }  // namespace
 
 struct LogMessage::LogMessageData final {
-  LogMessageData(absl::string_view file, int line,
-                 absl::LogSeverity severity, absl::Time timestamp);
+  static constexpr size_t kPoolCapacity = 16;
+  ABSL_CONST_INIT static ObjectPool<LogMessageData, kPoolCapacity> pool;
+
+  LogMessageData(absl::string_view file, int line, absl::LogSeverity severity,
+                 absl::Time timestamp) {
+    Reset(file, line, severity, timestamp);
+  }
   LogMessageData(const LogMessageData&) = delete;
   LogMessageData& operator=(const LogMessageData&) = delete;
 
+  void Reset(absl::string_view file, int line, absl::LogSeverity severity,
+             absl::Time timestamp);
+
   // `LogEntry` sent to `LogSink`s; contains metadata.
   absl::LogEntry entry;
 
@@ -169,7 +180,9 @@
   // non-sink targets (e.g. stderr, log files).
   bool extra_sinks_only;
 
-  std::ostream manipulated;  // ostream with IO manipulators applied
+  // Lazily initialized ostream with IO manipulators applied.
+  std::optional<std::ostream> manipulated;
+  bool manipulated_used;
 
   // A `logging.proto.Event` proto message is built into `encoded_buf`.
   std::array<char, kLogMessageBufferSize> encoded_buf;
@@ -200,12 +213,21 @@
   void FinalizeEncodingAndFormat();
 };
 
-LogMessage::LogMessageData::LogMessageData(absl::string_view file,
-                                           int line, absl::LogSeverity severity,
-                                           absl::Time timestamp)
-    : extra_sinks_only(false), manipulated(nullptr) {
-  // Legacy defaults for LOG's ostream:
-  manipulated.setf(std::ios_base::showbase | std::ios_base::boolalpha);
+ABSL_CONST_INIT ObjectPool<LogMessage::LogMessageData,
+                           LogMessage::LogMessageData::kPoolCapacity>
+    LogMessage::LogMessageData::pool;
+
+void LogMessage::LogMessageData::Reset(absl::string_view file, int line,
+                                       absl::LogSeverity severity,
+                                       absl::Time timestamp) {
+  first_fatal = false;
+  fail_quietly = false;
+  is_perror = false;
+  extra_sinks.clear();
+  extra_sinks.shrink_to_fit();
+  extra_sinks_only = false;
+  manipulated_used = false;
+  encoded_remaining_actual_do_not_use_directly = absl::Span<char>();
   entry.full_filename_ = file;
   entry.base_filename_ = Basename(file);
   entry.line_ = line;
@@ -214,6 +236,13 @@
   entry.verbose_level_ = absl::LogEntry::kNoVerbosityLevel;
   entry.timestamp_ = timestamp;
   entry.tid_ = absl::base_internal::GetCachedTID();
+  entry.text_message_with_prefix_and_newline_and_nul_ =
+      absl::Span<const char>();
+  entry.prefix_len_ = 0;
+  entry.encoding_ = absl::string_view();
+  if (!entry.stacktrace_.empty()) {
+    entry.stacktrace_ = std::string();
+  }
 }
 
 void LogMessage::LogMessageData::InitializeEncodingAndFormat() {
@@ -278,12 +307,7 @@
   : LogMessage(absl::string_view(file), line, severity) {}
 LogMessage::LogMessage(absl::string_view file, int line,
                        absl::LogSeverity severity)
-    : data_(
-          std::make_unique<LogMessageData>(file, line, severity, absl::Now())) {
-  data_->first_fatal = false;
-  data_->is_perror = false;
-  data_->fail_quietly = false;
-
+    : data_(LogMessageData::pool.Acquire(file, line, severity, absl::Now())) {
   // This logs a backtrace even if the location is subsequently changed using
   // AtLocation.  This quirk, and the behavior when AtLocation is called twice,
   // are fixable but probably not worth fixing.
@@ -298,7 +322,7 @@
     : LogMessage(file, line, absl::LogSeverity::kError) {}
 
 // This cannot go in the header since LogMessageData is defined in this file.
-LogMessage::~LogMessage() = default;
+LogMessage::~LogMessage() { LogMessageData::pool.Release(std::move(data_)); }
 
 LogMessage& LogMessage::AtLocation(absl::string_view file, int line) {
   data_->entry.full_filename_ = file;
@@ -437,14 +461,16 @@
   return *this;
 }
 
-LogMessage& LogMessage::operator<<(std::ostream& (*m)(std::ostream& os)) {
+LogMessage& LogMessage::operator<<(
+    std::ostream& (*absl_nonnull m)(std::ostream& os)) {
   OstreamView view(*data_);
-  data_->manipulated << m;
+  view.stream() << m;
   return *this;
 }
-LogMessage& LogMessage::operator<<(std::ios_base& (*m)(std::ios_base& os)) {
+LogMessage& LogMessage::operator<<(
+    std::ios_base& (*absl_nonnull m)(std::ios_base& os)) {
   OstreamView view(*data_);
-  data_->manipulated << m;
+  view.stream() << m;
   return *this;
 }
 // NOLINTBEGIN(runtime/int)
@@ -515,11 +541,23 @@
                          &encoded_remaining_copy_);
   setp(encoded_remaining_copy_.data(),
        encoded_remaining_copy_.data() + encoded_remaining_copy_.size());
-  data_.manipulated.rdbuf(this);
+  if (!std::exchange(data_.manipulated_used, true)) {
+    if (!data_.manipulated.has_value()) {
+      data_.manipulated.emplace(nullptr);
+    }
+    data_.manipulated->clear();
+    data_.manipulated->flags(std::ios_base::dec | std::ios_base::skipws |
+                             std::ios_base::showbase |
+                             std::ios_base::boolalpha);
+    data_.manipulated->precision(6);
+    data_.manipulated->width(0);
+    data_.manipulated->fill(' ');
+  }
+  data_.manipulated->rdbuf(this);
 }
 
 LogMessage::OstreamView::~OstreamView() {
-  data_.manipulated.rdbuf(nullptr);
+  data_.manipulated->rdbuf(nullptr);
   if (!string_start_.data()) {
     // The second field header didn't fit.  Whether the first one did or not, we
     // shouldn't commit `encoded_remaining_copy_`, and we also need to zero the
@@ -536,7 +574,7 @@
   data_.encoded_remaining() = encoded_remaining_copy_;
 }
 
-std::ostream& LogMessage::OstreamView::stream() { return data_.manipulated; }
+std::ostream& LogMessage::OstreamView::stream() { return *data_.manipulated; }
 
 bool LogMessage::IsFatal() const {
   return data_->entry.log_severity() == absl::LogSeverity::kFatal &&
diff --git a/absl/log/internal/object_pool.h b/absl/log/internal/object_pool.h
new file mode 100644
index 0000000..7ad2337
--- /dev/null
+++ b/absl/log/internal/object_pool.h
@@ -0,0 +1,140 @@
+// Copyright 2026 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: log/internal/object_pool.h
+// -----------------------------------------------------------------------------
+//
+// This file declares `class absl::log_internal::ObjectPool<T, kCapacity>`, a
+// fixed-capacity, lock-free object pool for reusable objects with static
+// storage duration.
+
+#ifndef ABSL_LOG_INTERNAL_OBJECT_POOL_H_
+#define ABSL_LOG_INTERNAL_OBJECT_POOL_H_
+
+#include <atomic>
+#include <cstddef>
+#include <memory>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/sysinfo.h"  // IWYU pragma: keep
+#include "absl/base/nullability.h"
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace log_internal {
+
+// A fixed-capacity, lock-free object pool of up to `kCapacity` reusable `T`
+// instances.
+//
+// `ObjectPool` is `constexpr`-constructible (supporting `ABSL_CONST_INIT`
+// static storage duration) and trivially destructible; pooled instances are
+// intentionally never destroyed at process exit so that usage during static
+// destruction remains safe.
+//
+// `T` must be constructible from the arguments passed to `Acquire(args...)` and
+// must provide a `void Reset(args...)` member function with a matching
+// signature to reinitialize a previously pooled instance.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable \
+                : 4324)  // structure was padded due to alignment specifier
+#endif
+template <typename T, size_t kCapacity>
+class ObjectPool final {
+  static_assert(kCapacity > 0, "ObjectPool capacity must be positive.");
+
+ public:
+  constexpr ObjectPool() = default;
+  ObjectPool(const ObjectPool&) = delete;
+  ObjectPool& operator=(const ObjectPool&) = delete;
+
+  // Acquires a `T` instance initialized with `args...`.
+  //
+  // If a pool slot is available, either lazily allocates a new `T` in that
+  // slot or calls `ptr->Reset(args...)` on the existing instance. If all
+  // `kCapacity` slots are concurrently in use, allocates a temporary overflow
+  // `T` on the heap.
+  template <typename... Args>
+  absl_nonnull std::unique_ptr<T> Acquire(Args&&... args) {
+    const size_t start = GetSlotHint();
+    for (size_t i = 0; i < kCapacity; ++i) {
+      const size_t idx = (start + i) % kCapacity;
+      Slot& slot = slots_[idx];
+      if (!slot.in_use.load(std::memory_order_relaxed) &&
+          !slot.in_use.exchange(true, std::memory_order_acquire)) {
+        SetSlotHint(idx);
+        T* ptr = slot.ptr.load(std::memory_order_relaxed);
+        if (ptr == nullptr) {
+          ptr = new T(std::forward<Args>(args)...);
+          slot.ptr.store(ptr, std::memory_order_relaxed);
+        } else {
+          ptr->Reset(std::forward<Args>(args)...);
+        }
+        return std::unique_ptr<T>(ptr);
+      }
+    }
+    return std::make_unique<T>(std::forward<Args>(args)...);
+  }
+
+  // Returns `item` to the pool if it belongs to one of the pool's slots, or
+  // deletes it if it was an overflow allocation.
+  void Release(std::unique_ptr<T> item) {
+    if (item == nullptr) return;
+    const size_t start = GetSlotHint();
+    for (size_t i = 0; i < kCapacity; ++i) {
+      Slot& slot = slots_[(start + i) % kCapacity];
+      if (slot.ptr.load(std::memory_order_relaxed) == item.get()) {
+        item.release();
+        slot.in_use.store(false, std::memory_order_release);
+        return;
+      }
+    }
+  }
+
+ private:
+  struct alignas(ABSL_CACHELINE_SIZE) Slot {
+    constexpr Slot() : in_use(false), ptr(nullptr) {}
+    std::atomic<bool> in_use;
+    std::atomic<T*> ptr;
+  };
+
+#ifdef ABSL_HAVE_THREAD_LOCAL
+  static size_t& SlotHint() {
+    ABSL_CONST_INIT thread_local size_t slot_hint = 0;
+    return slot_hint;
+  }
+  static size_t GetSlotHint() { return SlotHint(); }
+  static void SetSlotHint(size_t idx) { SlotHint() = idx; }
+#else
+  static size_t GetSlotHint() {
+    return static_cast<size_t>(absl::base_internal::GetCachedTID()) % kCapacity;
+  }
+  static void SetSlotHint(size_t) {}
+#endif
+
+  Slot slots_[kCapacity];
+};
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+}  // namespace log_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_LOG_INTERNAL_OBJECT_POOL_H_
diff --git a/absl/log/internal/object_pool_test.cc b/absl/log/internal/object_pool_test.cc
new file mode 100644
index 0000000..ac23954
--- /dev/null
+++ b/absl/log/internal/object_pool_test.cc
@@ -0,0 +1,177 @@
+// Copyright 2026 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/log/internal/object_pool.h"
+
+#include <atomic>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <thread>  // NOLINT(build/c++11)
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace log_internal {
+namespace {
+
+struct TestItem {
+  struct Counters {
+    std::atomic<int> constructions{0};
+    std::atomic<int> resets{0};
+    std::atomic<int> destructions{0};
+  };
+
+  TestItem(Counters* counters_arg, int value_arg, std::string label_arg)
+      : counters(counters_arg), value(value_arg), label(std::move(label_arg)) {
+    counters->constructions.fetch_add(1, std::memory_order_relaxed);
+  }
+
+  TestItem(const TestItem&) = delete;
+  TestItem& operator=(const TestItem&) = delete;
+
+  ~TestItem() {
+    counters->destructions.fetch_add(1, std::memory_order_relaxed);
+  }
+
+  void Reset(Counters* counters_arg, int value_arg, std::string label_arg) {
+    counters = counters_arg;
+    value = value_arg;
+    label = std::move(label_arg);
+    counters->resets.fetch_add(1, std::memory_order_relaxed);
+  }
+
+  Counters* counters;
+  int value;
+  std::string label;
+};
+
+static_assert(std::is_trivially_destructible_v<ObjectPool<TestItem, 4>>);
+
+ABSL_CONST_INIT ObjectPool<TestItem, 4> const_init_pool;
+
+TEST(ObjectPoolTest, AcquireAndReleaseReusesPooledObject) {
+  TestItem::Counters counters;
+  std::unique_ptr<TestItem> first =
+      const_init_pool.Acquire(&counters, 10, "first");
+  ASSERT_NE(first, nullptr);
+  const TestItem* first_ptr = first.get();
+  EXPECT_EQ(first->value, 10);
+  EXPECT_EQ(first->label, "first");
+  EXPECT_EQ(counters.constructions.load(), 1);
+  EXPECT_EQ(counters.resets.load(), 0);
+  EXPECT_EQ(counters.destructions.load(), 0);
+
+  const_init_pool.Release(std::move(first));
+  EXPECT_EQ(counters.destructions.load(), 0);
+
+  std::unique_ptr<TestItem> second =
+      const_init_pool.Acquire(&counters, 20, "second");
+  ASSERT_NE(second, nullptr);
+  EXPECT_EQ(second.get(), first_ptr);
+  EXPECT_EQ(second->value, 20);
+  EXPECT_EQ(second->label, "second");
+  EXPECT_EQ(counters.constructions.load(), 1);
+  EXPECT_EQ(counters.resets.load(), 1);
+  EXPECT_EQ(counters.destructions.load(), 0);
+
+  const_init_pool.Release(std::move(second));
+  EXPECT_EQ(counters.destructions.load(), 0);
+}
+
+TEST(ObjectPoolTest, OverflowAllocatesAndDeletesWhenPoolExhausted) {
+  ABSL_CONST_INIT static ObjectPool<TestItem, 2> pool;
+  TestItem::Counters counters;
+
+  std::unique_ptr<TestItem> first = pool.Acquire(&counters, 1, "one");
+  std::unique_ptr<TestItem> second = pool.Acquire(&counters, 2, "two");
+  std::unique_ptr<TestItem> overflow = pool.Acquire(&counters, 3, "three");
+
+  EXPECT_NE(first.get(), second.get());
+  EXPECT_NE(first.get(), overflow.get());
+  EXPECT_NE(second.get(), overflow.get());
+  EXPECT_EQ(counters.constructions.load(), 3);
+  EXPECT_EQ(counters.destructions.load(), 0);
+
+  // Releasing the overflow item must destroy it immediately because it does not
+  // belong to any of the pool's slots.
+  pool.Release(std::move(overflow));
+  EXPECT_EQ(counters.destructions.load(), 1);
+
+  const TestItem* first_ptr = first.get();
+  const TestItem* second_ptr = second.get();
+  pool.Release(std::move(first));
+  pool.Release(std::move(second));
+  EXPECT_EQ(counters.destructions.load(), 1);
+
+  // Subsequent acquisition reuses one of the pooled items.
+  std::unique_ptr<TestItem> reused = pool.Acquire(&counters, 4, "four");
+  EXPECT_TRUE(reused.get() == first_ptr || reused.get() == second_ptr);
+  EXPECT_EQ(reused->value, 4);
+  EXPECT_EQ(reused->label, "four");
+  EXPECT_EQ(counters.constructions.load(), 3);
+  EXPECT_EQ(counters.resets.load(), 1);
+  pool.Release(std::move(reused));
+}
+
+TEST(ObjectPoolTest, ReleaseNullptrIsNoOp) {
+  ABSL_CONST_INIT static ObjectPool<TestItem, 2> pool;
+  pool.Release(nullptr);
+}
+
+TEST(ObjectPoolTest, ConcurrentAcquireAndRelease) {
+  ABSL_CONST_INIT static ObjectPool<TestItem, 4> pool;
+  TestItem::Counters counters;
+
+  constexpr size_t kNumThreads = 16;
+  static constexpr int kIterationsPerThread = 200;
+  std::vector<std::thread> threads;
+  threads.reserve(kNumThreads);
+  for (size_t t = 0; t < kNumThreads; ++t) {
+    threads.emplace_back([&counters, t]() {
+      const std::string expected_label = "thread_" + std::to_string(t);
+      for (int i = 0; i < kIterationsPerThread; ++i) {
+        const int expected_val = static_cast<int>(t) * 1000 + i;
+        std::unique_ptr<TestItem> item =
+            pool.Acquire(&counters, expected_val, expected_label);
+        EXPECT_EQ(item->value, expected_val);
+        EXPECT_EQ(item->label, expected_label);
+        item->value = -expected_val;
+        EXPECT_EQ(item->value, -expected_val);
+        pool.Release(std::move(item));
+      }
+    });
+  }
+  for (std::thread& thread : threads) {
+    thread.join();
+  }
+
+  const int total_acquires =
+      static_cast<int>(kNumThreads) * kIterationsPerThread;
+  EXPECT_EQ(counters.constructions.load() + counters.resets.load(),
+            total_acquires);
+  // Up to 4 items remain live in the pool; any overflow items were destroyed.
+  EXPECT_LE(counters.constructions.load() - counters.destructions.load(), 4);
+}
+
+}  // namespace
+}  // namespace log_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/log/log_benchmark.cc b/absl/log/log_benchmark.cc
index 50a64ea..878001b 100644
--- a/absl/log/log_benchmark.cc
+++ b/absl/log/log_benchmark.cc
@@ -95,6 +95,29 @@
 }
 BENCHMARK(BM_EnabledLogOverhead);
 
+class LocalNullLogSink : public absl::LogSink {
+ public:
+  void Send(const absl::LogEntry&) override {}
+};
+
+static void BM_EnabledLogToSinkString(benchmark::State& state) {
+  absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
+  LocalNullLogSink sink;
+  for (auto _ : state) {
+    LOG(INFO).ToSinkOnly(&sink) << "hello world";
+  }
+}
+BENCHMARK(BM_EnabledLogToSinkString)->ThreadRange(1, 16);
+
+static void BM_EnabledLogToSinkInt(benchmark::State& state) {
+  absl::SetMinLogLevel(absl::LogSeverityAtLeast::kInfo);
+  LocalNullLogSink sink;
+  for (auto _ : state) {
+    LOG(INFO).ToSinkOnly(&sink) << "value: " << 42;
+  }
+}
+BENCHMARK(BM_EnabledLogToSinkInt)->ThreadRange(1, 16);
+
 static void BM_VlogIsOnOverhead(benchmark::State& state) {
   // It would make sense to do this only when state.thread_index == 0,
   // but thread_index is an int on some platforms (e.g. Android) and a
diff --git a/absl/log/log_format_test.cc b/absl/log/log_format_test.cc
index b792d38..48cb4db 100644
--- a/absl/log/log_format_test.cc
+++ b/absl/log/log_format_test.cc
@@ -25,6 +25,7 @@
 #include <string>
 #include <string_view>
 #include <type_traits>
+#include <vector>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -1950,6 +1951,47 @@
   LOG(INFO) << std::setfill('0') << std::setw(8) << value;
 }
 
+TEST(ManipulatorLogFormatTest, ManipulatorsDoNotLeakAcrossPooledMessages) {
+  struct BufferAndMessageCaptureSink : public absl::LogSink {
+    void Send(const absl::LogEntry& entry) override {
+      buffers.push_back(entry.text_message_with_prefix_and_newline().data());
+      messages.emplace_back(entry.text_message());
+    }
+    std::vector<const char*> buffers;
+    std::vector<std::string> messages;
+  } sink;
+
+  // 1. Log without touching OstreamView (leaves std::optional<std::ostream>
+  // uninitialized or unused for this message).
+  constexpr absl::string_view kPlainMessage = "plain string_view";
+  LOG(INFO).ToSinkOnly(&sink) << kPlainMessage;
+
+  // 2. Log with non-default stream manipulators and stream error state bits on
+  // the same pooled buffer.
+  LOG(INFO).ToSinkOnly(&sink)
+      << std::hex << std::uppercase << std::noshowbase << std::noboolalpha
+      << std::scientific << std::setprecision(2) << std::setfill('*')
+      << std::left << std::setw(8) << 255 << " " << true << " " << 1.5
+      << +[](std::ostream& os) -> std::ostream& {
+    os.setstate(std::ios_base::failbit | std::ios_base::badbit |
+                std::ios_base::eofbit);
+    return os;
+  };
+
+  // 3. Log again without manipulators; verify the same pooled LogMessageData
+  // buffer is reused and all default ostream flags/precision/width/fill/rdstate
+  // are restored.
+  LOG(INFO).ToSinkOnly(&sink)
+      << 255 << " " << true << " " << 1.5 << " " << std::setw(4) << 7;
+
+  ASSERT_EQ(sink.messages.size(), 3u);
+  EXPECT_EQ(sink.buffers[0], sink.buffers[1]);
+  EXPECT_EQ(sink.buffers[1], sink.buffers[2]);
+  EXPECT_EQ(sink.messages[0], "plain string_view");
+  EXPECT_EQ(sink.messages[1], "FF****** 1 1.50E+00");
+  EXPECT_EQ(sink.messages[2], "255 true 1.5    7");
+}
+
 class FromCustomClass {};
 std::ostream& operator<<(std::ostream& os, const FromCustomClass&) {
   return os << "FromCustomClass{}" << std::hex;