為了在已經發生很多事情的地方檢測潛在的記憶體泄漏,我使用了如下所示的構建測驗。主要思想是擁有一個實體,不再參考它并讓垃圾收集器收集它。我不想關注這是否是一項好技術(在我的特定情況下它做得很好),但我想關注以下問題:
下面的代碼在 .NetFramework 4.8 上運行良好,但在 .Net 5 上不起作用。為什么?
[Test]
public void ConceptualMemoryLeakTest()
{
WeakReference weakReference;
{
object myObject = new object();
weakReference = new WeakReference(myObject);
myObject = null;
Assert.Null(myObject);
}
Assert.True(weakReference.IsAlive); // instance not collected by GC
GC.Collect();
GC.WaitForPendingFinalizers();
GC.WaitForFullGCComplete();
GC.Collect();
Assert.False(weakReference.IsAlive); // instance collected by GC
}
您可以看到主要思想是使用 aWeakReference和 useIsAlive來確定實體是否被 GC 洗掉。新的 CLR(源自 dotnet 核心)中的規則是如何變化的?我知道這里所做的并不依賴于指定的內容。相反,我只是利用了我在 NetFramework 4.8 中看到的 CLR 的行為。
您是否知道如何再次獲得同樣適用于 .Net 5 的類似內容?
uj5u.com熱心網友回復:
原因很可能是分層編譯。簡單來說,分層編譯會(對于某些條件下的某些方法)首先編譯一個方法的粗略、低優化版本,然后在必要時準備一個更好的優化版本。這在 .NET 5(和 .NET Core 3 )中默認啟用,但在 .NET 4.8 中不可用。
在您的情況下,結果是您的方法是使用提到的“快速”編譯進行編譯的,并且沒有足夠優化以使您的代碼按預期作業(即myObject變數的生命周期延長到方法結束)。即使您在啟用優化的發布模式下編譯,并且沒有附加任何除錯器,情況也是如此。
您可以通過添加以下內容來禁用分層編譯:
<TieredCompilation>false</TieredCompilation>
<PropertyGroup>對于 .NET 5 專案的某些內部 csproj 檔案,您將觀察到與在 .NET 4.8 情況下相同的行為。
另一種選擇(除了將變數移動到另一種方法并WeakReference從中回傳)是使用:
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
ConceptualMemoryLeakTest方法上的屬性。
uj5u.com熱心網友回復:
實際上,通過評論和答案中提供的提示,我意識到將實體移動到一個單獨的方法并防止行內它是有效的:
[MethodImpl(MethodImplOptions.NoInlining)]
private WeakReference CreateWeakReference()
{
object myObject = new object();
return new WeakReference(myObject);
}
[Test]
public void ConceptualMemoryLeakTest()
{
WeakReference weakReference = CreateWeakReference();
Assert.True(weakReference.IsAlive);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.WaitForFullGCComplete();
GC.Collect();
Assert.False(weakReference.IsAlive);
}
這不需要
<TieredCompilation>false</TieredCompilation>
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/323404.html
標籤:C# 。网 垃圾收集 .net-5 .net-framework-4.8
下一篇:如何在C#.net中創建DTO
