The DeferredInvocationContext only existed to satisfy the requirement
in ThreadEventQueue that each event has an EventReceiver. However,
deferred_invoke() was not even using the EventReceiver to call its
callback. Therefore, we don't need to allocate one for every deferred
invocation.
This also prevents WeakPtr::strong_ref() from racing and leaking the
context object when invoking a function across threads.
The inline capacity on ThreadEventQueue::Private::queued_events caused
us to reserve (and importantly, not initialize!) 2 KiB of stack memory
when entering ThreadEventQueue::process().
This was causing any leftover pointers to GC-allocated objects within
that memory range to keep those objects alive, even when all other
references were gone.