mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-02 07:23:41 +02:00
gobject: shrink WeakRefStack during release-all
It feels ugly to leave the buffer not sized right. We call g_object_weak_release_all() during g_object_real_dispose() and right before finalize. In most cases, we expect that the loop iterates until there are no weak notifications left (in which case the entire WeakRefStack is freed). In that case, there is no need to shrink the buffer, because it's going to be released soon anyway. Note that no new weak references can be registered after finalize (as the ref count already dropped to zero). However, new weak referenes can be registered during dispose (either during the last g_object_unref() or during g_object_run_dispose()). In that case, I feel it is nice to bring the buffer size right again. We don't know how long the object will continue to live afterwards, so let's trim the extra allocation.
This commit is contained in:
@@ -3753,6 +3753,38 @@ _weak_ref_stack_free (WeakRefStack *wstack)
|
||||
g_free (wstack);
|
||||
}
|
||||
|
||||
G_ALWAYS_INLINE static inline gboolean
|
||||
_weak_ref_stack_needs_shrink (WeakRefStack *wstack)
|
||||
{
|
||||
return wstack->n_weak_refs <= wstack->alloc_size / 4u;
|
||||
}
|
||||
|
||||
G_ALWAYS_INLINE static inline void
|
||||
_weak_ref_stack_maybe_shrink (WeakRefStack **p_wstack, gpointer *data)
|
||||
{
|
||||
WeakRefStack *wstack = *p_wstack;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
g_assert (wstack->n_weak_refs > 0);
|
||||
#endif
|
||||
|
||||
if (!G_UNLIKELY (_weak_ref_stack_needs_shrink (wstack)))
|
||||
return;
|
||||
|
||||
/* There is a loop here to find the right allocation size, because during
|
||||
* g_object_weak_release_all() we don't shrink every time an entry is
|
||||
* removed. */
|
||||
do
|
||||
{
|
||||
wstack->alloc_size = wstack->alloc_size / 2u;
|
||||
}
|
||||
while (G_UNLIKELY (_weak_ref_stack_needs_shrink (wstack)));
|
||||
|
||||
wstack = g_realloc (wstack, WEAK_REF_STACK_ALLOC_SIZE (wstack->alloc_size));
|
||||
*data = wstack;
|
||||
*p_wstack = wstack;
|
||||
}
|
||||
|
||||
G_ALWAYS_INLINE static inline void
|
||||
_weak_ref_stack_update_release_all_state (WeakRefStack *wstack, guint idx)
|
||||
{
|
||||
@@ -3917,12 +3949,7 @@ handle_weak_ref_found:
|
||||
sizeof (wstack->weak_refs[idx]) * (wstack->n_weak_refs - idx));
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (wstack->n_weak_refs <= wstack->alloc_size / 4u))
|
||||
{
|
||||
wstack->alloc_size = wstack->alloc_size / 2u;
|
||||
wstack = g_realloc (wstack, WEAK_REF_STACK_ALLOC_SIZE (wstack->alloc_size));
|
||||
*data = wstack;
|
||||
}
|
||||
_weak_ref_stack_maybe_shrink (&wstack, data);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -4049,8 +4076,14 @@ g_object_weak_release_all_cb (gpointer *data,
|
||||
&wstack->weak_refs[1],
|
||||
sizeof (wstack->weak_refs[0]) * wstack->n_weak_refs);
|
||||
|
||||
/* Don't bother to shrink the buffer. Most likely the object gets
|
||||
* destroyed soon after. */
|
||||
if (wdata->release_all_done)
|
||||
{
|
||||
/* We maybe-shrink on each g_object_weak_unref(). During release-all,
|
||||
* we usually don't shrink, because we expect that we pop all entries.
|
||||
* In this case, we are now done and additional entries were subscribed
|
||||
* in the meantime. In this case also maybe-shrink. */
|
||||
_weak_ref_stack_maybe_shrink (&wstack, data);
|
||||
}
|
||||
}
|
||||
|
||||
return wdata;
|
||||
|
Reference in New Issue
Block a user