Skip to content

Commit 4a548dc

Browse files
committed
Trigger GC for actors when they tell the cycle detector they're blocked
Prior to this commit, if an actor blocked, it did not run GC to free any memory it no longer needed. This would result in blocked actors holding on to (potentially lots of) memory unnecessarily. This commit causes GC to be triggered when the cycle detector asks an actor if it is blocked and the actor responds telling the cycle detector that it is blocked and also when the actor initially tells the cycle detector that it is blocked. This should result in memory being held by blocked actors to be freed more quickly even if the cycle detector doesn't end up detecting a cycle and reaping the actors.
1 parent f7996d0 commit 4a548dc

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

src/libponyrt/actor/actor.c

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ static void send_unblock(pony_actor_t* actor)
9090
ponyint_cycle_unblock(actor);
9191
}
9292

93+
static void send_block(pony_actor_t* actor)
94+
{
95+
// We're blocked, send block message.
96+
set_flag(actor, FLAG_BLOCKED_SENT);
97+
set_flag(actor, FLAG_CD_CONTACTED);
98+
pony_assert(ctx->current == actor);
99+
ponyint_cycle_block(actor, &actor->gc);
100+
101+
// trigger a GC if we're sending a block message to the CD
102+
// GC will get run next time `try_gc` is called which should
103+
// happen once all messages get processed in the messageq
104+
// at the time `pony_actor_run` was called if not earlier
105+
// when an app message is processed
106+
pony_triggergc(ctx);
107+
}
108+
93109
static bool handle_message(pony_ctx_t* ctx, pony_actor_t* actor,
94110
pony_msg_t* msg)
95111
{
@@ -192,13 +208,9 @@ static bool handle_message(pony_ctx_t* ctx, pony_actor_t* actor,
192208
#endif
193209

194210
pony_assert(!ponyint_is_cycle(actor));
211+
195212
if(has_flag(actor, FLAG_BLOCKED) && !has_flag(actor, FLAG_BLOCKED_SENT))
196-
{
197-
// We're blocked, send block message.
198-
set_flag(actor, FLAG_BLOCKED_SENT);
199-
pony_assert(ctx->current == actor);
200-
ponyint_cycle_block(actor, &actor->gc);
201-
}
213+
send_block(actor);
202214

203215
return false;
204216
}
@@ -418,9 +430,12 @@ bool ponyint_actor_run(pony_ctx_t* ctx, pony_actor_t* actor, bool polling)
418430
// in the future we will wait for the CD to reach out and ask
419431
// if we're blocked or not.
420432
// But, only if gc.rc > 0 because if gc.rc == 0 we are a zombie.
421-
set_flag(actor, FLAG_BLOCKED_SENT);
422-
set_flag(actor, FLAG_CD_CONTACTED);
423-
ponyint_cycle_block(actor, &actor->gc);
433+
send_block(actor);
434+
435+
// Try and run GC because we're blocked and sending a block message
436+
// to the CD and we're past the normal point at which `try_gc` is
437+
// called as part of this function
438+
try_gc(ctx, actor);
424439
}
425440

426441
}
@@ -479,9 +494,7 @@ bool ponyint_actor_run(pony_ctx_t* ctx, pony_actor_t* actor, bool polling)
479494
// have a reference to this actor (rc is 0) so another actor can not
480495
// send it an application message that results this actor becoming
481496
// unblocked (which would create a race condition).
482-
set_flag(actor, FLAG_BLOCKED_SENT);
483-
set_flag(actor, FLAG_CD_CONTACTED);
484-
ponyint_cycle_block(actor, &actor->gc);
497+
send_block(actor);
485498
}
486499
}
487500
}
@@ -866,7 +879,10 @@ void* pony_alloc_large_final(pony_ctx_t* ctx, size_t size)
866879
PONY_API void pony_triggergc(pony_ctx_t* ctx)
867880
{
868881
pony_assert(ctx->current != NULL);
869-
ctx->current->heap.next_gc = 0;
882+
883+
// only trigger gc if actor allocated something on the heap
884+
if(ctx->current->heap.used > 0)
885+
ctx->current->heap.next_gc = 0;
870886
}
871887

872888
PONY_API void pony_schedule(pony_ctx_t* ctx, pony_actor_t* actor)

0 commit comments

Comments
 (0)