diff --git a/src/workerd/io/io-context.c++ b/src/workerd/io/io-context.c++ index c3aba95ade3..a6b8e96422c 100644 --- a/src/workerd/io/io-context.c++ +++ b/src/workerd/io/io-context.c++ @@ -1062,12 +1062,22 @@ kj::Own IoContext::getCacheClient() { jsg::AsyncContextFrame::StorageScope IoContext::makeAsyncTraceScope( Worker::Lock& lock, kj::Maybe spanParentOverride) { + static const SpanParent dummySpanParent = nullptr; + jsg::Lock& js = lock; kj::Own spanParent; KJ_IF_SOME(spo, kj::mv(spanParentOverride)) { spanParent = kj::heap(kj::mv(spo)); } else { - spanParent = kj::heap(getMetrics().getSpan()); + // TODO(cleanup): Can we also elide the other memory allocations for the (unused) storage + // scope if tracing is disabled? + if (!getMetrics().getSpan().isObserved()) { + // const_cast is ok: There's no state that could be changed in a non-observed span parent. + spanParent = kj::Own( + &const_cast(dummySpanParent), kj::NullDisposer::instance); + } else { + spanParent = kj::heap(getMetrics().getSpan()); + } } auto ioOwnSpanParent = IoContext::current().addObject(kj::mv(spanParent)); auto spanHandle = jsg::wrapOpaque(js.v8Context(), kj::mv(ioOwnSpanParent));