summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/erl_message.c
diff options
context:
space:
mode:
authorJohn Högberg <john@erlang.org>2022-04-08 09:44:07 +0200
committerJohn Högberg <john@erlang.org>2022-04-08 09:44:07 +0200
commit8f92654091efe5c3700df6a94dcb63a2fd954a1b (patch)
tree0e80ac88b52bd15d55f408181c860e1cdf9ac586 /erts/emulator/beam/erl_message.c
parentee8872b0f2528985306e8b2299920eb445a0c30f (diff)
parent9bc75265f3871c86774ba068f05bb40a6494981a (diff)
downloaderlang-8f92654091efe5c3700df6a94dcb63a2fd954a1b.tar.gz
Merge branch 'maint'
* maint: erts: Stop freeing heap fragments in `erts_factory_undo` erts: Stop freeing heap fragments in `erts_factory_undo`
Diffstat (limited to 'erts/emulator/beam/erl_message.c')
-rw-r--r--erts/emulator/beam/erl_message.c61
1 files changed, 30 insertions, 31 deletions
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index b87c0d06ba..51bf1f63f6 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -1137,6 +1137,10 @@ void erts_factory_proc_init(ErtsHeapFactory* factory, Process* p)
heap as that completely destroys the DEBUG emulators
performance. */
ErlHeapFragment *bp = p->mbuf;
+
+ factory->off_heap_saved.first = p->off_heap.first;
+ factory->off_heap_saved.overhead = p->off_heap.overhead;
+
factory->mode = FACTORY_HALLOC;
factory->p = p;
factory->hp_start = HEAP_TOP(p);
@@ -1150,8 +1154,6 @@ void erts_factory_proc_init(ErtsHeapFactory* factory, Process* p)
factory->message = NULL;
factory->off_heap_saved.first = p->off_heap.first;
factory->off_heap_saved.overhead = p->off_heap.overhead;
- factory->heap_frags_saved = bp;
- factory->heap_frags_saved_used = bp ? bp->used_size : 0;
factory->heap_frags = NULL; /* not used */
factory->alloc_type = 0; /* not used */
@@ -1164,6 +1166,13 @@ void erts_factory_proc_prealloc_init(ErtsHeapFactory* factory,
Sint size)
{
ErlHeapFragment *bp = p->mbuf;
+
+ /* `heap_frags_saved_used` must be set _BEFORE_ we call `HAlloc`, as that
+ * may update `bp->used_size` and prevent us from undoing the changes later
+ * on. */
+ factory->heap_frags_saved = bp;
+ factory->heap_frags_saved_used = bp ? bp->used_size : 0;
+
factory->mode = FACTORY_HALLOC;
factory->p = p;
factory->original_htop = HEAP_TOP(p);
@@ -1178,8 +1187,6 @@ void erts_factory_proc_prealloc_init(ErtsHeapFactory* factory,
factory->message = NULL;
factory->off_heap_saved.first = p->off_heap.first;
factory->off_heap_saved.overhead = p->off_heap.overhead;
- factory->heap_frags_saved = bp;
- factory->heap_frags_saved_used = bp ? bp->used_size : 0;
factory->heap_frags = NULL; /* not used */
factory->alloc_type = 0; /* not used */
}
@@ -1557,40 +1564,32 @@ void erts_factory_undo(ErtsHeapFactory* factory)
}
if (factory->mode == FACTORY_HALLOC) {
- /* Free heap frags
- */
- bp = factory->p->mbuf;
- if (bp != factory->heap_frags_saved) {
- do {
- ErlHeapFragment *next_bp = bp->next;
- ASSERT(bp->off_heap.first == NULL);
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP_FRAG, (void *) bp,
- ERTS_HEAP_FRAG_SIZE(bp->alloc_size));
- bp = next_bp;
- } while (bp != factory->heap_frags_saved);
-
- factory->p->mbuf = bp;
+ /* Reset all the heap fragments we've added. Note that we CANNOT
+ * free them, as someone else might have grabbed a reference to
+ * them (e.g. the callers of `erts_gc_after_bif_call_lhf`).
+ *
+ * The GC will get rid of these later on. Note that we leave
+ * `p->mbuf_sz` untouched to keep the memory pressure of these
+ * fragments. */
+ for (bp = (factory->p)->mbuf;
+ bp != factory->heap_frags_saved;
+ bp = bp->next) {
+ ASSERT(bp->off_heap.first == NULL);
+ bp->used_size = 0;
}
- /* Rollback heap top
- */
+ /* Roll back the size of the latest fragment not allocated by us,
+ * as we may have used a part of it. */
+ if (bp != NULL) {
+ ASSERT(bp == factory->heap_frags_saved);
+ bp->used_size = factory->heap_frags_saved_used;
+ }
+ /* Roll back heap top */
ASSERT(HEAP_START(factory->p) <= factory->original_htop);
ASSERT(factory->original_htop <= HEAP_LIMIT(factory->p));
HEAP_TOP(factory->p) = factory->original_htop;
-
- /* Fix last heap frag */
- if (factory->heap_frags_saved) {
- ASSERT(factory->heap_frags_saved == factory->p->mbuf);
- if (factory->hp_start != factory->heap_frags_saved->mem)
- factory->heap_frags_saved->used_size = factory->heap_frags_saved_used;
- else {
- factory->p->mbuf = factory->p->mbuf->next;
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP_FRAG, factory->heap_frags_saved,
- ERTS_HEAP_FRAG_SIZE(factory->heap_frags_saved->alloc_size));
- }
- }
if (factory->message) {
ASSERT(factory->message->data.attached != ERTS_MSG_COMBINED_HFRAG);
ASSERT(!factory->message->data.heap_frag);