首页 > 解决方案 > instance.invokeMethod 内存泄漏

问题描述

我通过 .invokeMethod 对 C# 进行了很多调用,而我的 GarbageCollector 似乎令人窒息。显然我不太了解 Javascript/Blazor 互操作内存管理,所以希望你们中的一个可以提供帮助。

我正在设置 window.requestAnimationFrame 以回调 c#。JS看起来如下:

<script type="text/javascript">

    window.anim = {
        start: function (instance) {
            console.log('start');
            return window.requestAnimationFrame(function (timestamp) { anim.callback(instance); });
        },

        callback: function (instance) {
            instance.invokeMethod('IncrementCount');
            var callbackId = window.requestAnimationFrame(function (timestamp) { anim.callback(instance); });

        },

        stop: function (callbackId) {
            window.cancelAnimationFrame(callbackId);
        }
    };

</script>

我的 Razor 页面如下所示:

@page "/counter"
@inject IJSRuntime JSRuntime;

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var dotNetReference = DotNetObjectReference.Create(this);
            await JSRuntime.InvokeAsync<string>("window.anim.start", dotNetReference);
        }
    }

    [JSInvokable("IncrementCount")]
    public void IncrementCount()
    {
        currentCount++;

        StateHasChanged();
    }
}

我的 GarbageCollector 很快就会出现“GC_MINOR: (Nursery full)”消息,而我的 System / JSArrayBufferData 看起来很大。从文档中,我可以收集到应该处理的对象,但是在这样的情况下它们也应该被处理吗?(在哪里?!)

(更新:好的,所以 System / JSArrayBufferData 总是很大,即使在运行 Blazor 示例时也是如此。所以我想这本身并没有任何指示......但这仍然对我没有帮助)

这是一个问题的原因是,当我尝试做任何有意义的事情时,GC VERY 经常会启动。这里的例子只是为了说明即使在最简单的情况下也会发生这种情况。

谢谢!

/托马斯

标签: javascriptvisual-studioblazor

解决方案


这可能不起作用,并且作为对原始问题的评论的更完整建议添加。我会鼓励 OP 评论这是多么有效,也鼓励其他任何人纠正我的错误,以便我可以了解更多相关信息。

由于“IJSRuntime”填满了内存,这背后的想法是运行时的生命周期范围可能比它应该的要长得多,并且由于 Blazor 是一个有状态的框架,因此状态正在被携带用它。

尝试使用OwningComponentBase将 JS 运行时的范围强制到组件的生命周期,而不是 Blazor Server 中的连接生命周期或作为 Blazor WASM 中的单例。设置应该只需要几行代码。在 Razor 文件的顶部:

@inherits OwningComponentBase

然后在@code 块中:

@code {

    // Property for the runtime, NOT injected here    
    public IJSRuntime Runtime { get; set; } 

    // Sets up the Runtime as a scoped service, so it will release and be available 
    // for Garbage Collection when the component is torn down
    protected override void OnInitialized()
    {
        Runtime = ScopedServices.GetRequiredService<IJSRuntime>();
    }

}

如果我的想法是正确的,这应该有助于内存管理。我鼓励其他可能对该主题更了解的人也可以评论或编辑这篇文章。

这是在此处遵循有关 Blazor 中范围服务生命周期的官方文档。

希望这有帮助,请回来报告!


推荐阅读