Mono Continuations - store() 之后内存不断增加

发布于 2024-08-03 11:26:14 字数 2125 浏览 5 评论 0原文

这是 Mono Continuations 的 continuation_store (...)。从下面的代码来看,store() 似乎遵循这两个分支:

  1. cont->saved_stack && num_bytes <= cont->stack_alloc_size
    • 直接使用内存
  2. else
    • gc 释放已使用的内存,并创建一些新内存。

然而,奇怪的是,如果我重复使用 continuation_store(),内存使用量会增加,直到稍后的步骤完成一个巨大且滞后的 GC 操作。谁能解释为什么会发生这种情况?

谢谢

static int
continuation_store (MonoContinuation *cont, int state, MonoException **e)
{
    MonoLMF *lmf = mono_get_lmf ();
    gsize num_bytes;

    if (!cont->domain)
        *e =  mono_get_exception_argument ("cont", "Continuation not initialized");
    if (cont->domain != mono_domain_get () || cont->thread_id != GetCurrentThreadId ())
        *e = mono_get_exception_argument ("cont", "Continuation from another thread or domain");

    cont->lmf = lmf;
    cont->return_ip = __builtin_return_address (0);
    cont->return_sp = __builtin_frame_address (0);

    num_bytes = (char*)cont->top_sp - (char*)cont->return_sp;

    /*g_print ("store: %d bytes, sp: %p, ip: %p, lmf: %p\n", num_bytes, cont->return_sp, cont->return_ip, lmf);*/

    if (cont->saved_stack && num_bytes <= cont->stack_alloc_size) 
    {
        /* clear to avoid GC retention */
        if (num_bytes < cont->stack_used_size)
            memset ((char*)cont->saved_stack + num_bytes, 0, cont->stack_used_size - num_bytes);
    } 
    else 
    {
        tasklets_lock ();
        internal_init ();
        if (cont->saved_stack) {
            mono_g_hash_table_remove (keepalive_stacks, cont->saved_stack);
            mono_gc_free_fixed (cont->saved_stack);
        }
        cont->stack_used_size = num_bytes;
        cont->stack_alloc_size = num_bytes * 1.1;
        cont->saved_stack = mono_gc_alloc_fixed (cont->stack_alloc_size, NULL);
        mono_g_hash_table_insert (keepalive_stacks, cont->saved_stack, cont->saved_stack);
        tasklets_unlock ();
    }
    memcpy (cont->saved_stack, cont->return_sp, num_bytes);

    return state;
}

Here's Mono Continuations' continuation_store (...). From looking at the code below, it appears as though store() follows these two branches:

  1. cont->saved_stack && num_bytes <= cont->stack_alloc_size
    • use the memory directly
  2. else
    • gc free the used memory, and create some new memory.

However, the weird thing is if I repeatedly use continuation_store(), the memory usage increases until at a later step a huge and laggy GC operation is done. Can anyone explain why this happens?

Thanks

static int
continuation_store (MonoContinuation *cont, int state, MonoException **e)
{
    MonoLMF *lmf = mono_get_lmf ();
    gsize num_bytes;

    if (!cont->domain)
        *e =  mono_get_exception_argument ("cont", "Continuation not initialized");
    if (cont->domain != mono_domain_get () || cont->thread_id != GetCurrentThreadId ())
        *e = mono_get_exception_argument ("cont", "Continuation from another thread or domain");

    cont->lmf = lmf;
    cont->return_ip = __builtin_return_address (0);
    cont->return_sp = __builtin_frame_address (0);

    num_bytes = (char*)cont->top_sp - (char*)cont->return_sp;

    /*g_print ("store: %d bytes, sp: %p, ip: %p, lmf: %p\n", num_bytes, cont->return_sp, cont->return_ip, lmf);*/

    if (cont->saved_stack && num_bytes <= cont->stack_alloc_size) 
    {
        /* clear to avoid GC retention */
        if (num_bytes < cont->stack_used_size)
            memset ((char*)cont->saved_stack + num_bytes, 0, cont->stack_used_size - num_bytes);
    } 
    else 
    {
        tasklets_lock ();
        internal_init ();
        if (cont->saved_stack) {
            mono_g_hash_table_remove (keepalive_stacks, cont->saved_stack);
            mono_gc_free_fixed (cont->saved_stack);
        }
        cont->stack_used_size = num_bytes;
        cont->stack_alloc_size = num_bytes * 1.1;
        cont->saved_stack = mono_gc_alloc_fixed (cont->stack_alloc_size, NULL);
        mono_g_hash_table_insert (keepalive_stacks, cont->saved_stack, cont->saved_stack);
        tasklets_unlock ();
    }
    memcpy (cont->saved_stack, cont->return_sp, num_bytes);

    return state;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

节枝 2024-08-10 11:26:14

请注意,对 mono_gc_free_fixed 的调用在默认的 boehm 收集器中不会执行任何操作: https://github.com/mono/mono/blob/master/mono/metadata/boehm-gc.c#L528

else 分支只是从 keepalive_stacks 哈希表中删除内存。该哈希表保留对已分配内存的引用,因此不会被垃圾回收。一旦从该哈希表中删除指向已分配内存的指针,它将在下一次垃圾收集期间被回收。一旦达到一定的内存分配量,就会稍后触发此收集。

Note the call to mono_gc_free_fixed does nothing in the default boehm collector: https://github.com/mono/mono/blob/master/mono/metadata/boehm-gc.c#L528

The else branch just removes the memory from the keepalive_stacks hash table. This hash table keeps a reference to the allocated memory so it is not garbage collected. Once the pointer to the allocated memory is removed from this hash table, it will then be reclaimed during the next garbage collection. This collection is triggered at a later time once reaching a certain amount of memory allocation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文