日韩欧美人妻无码精品白浆,夜夜嗨AV免费入口,国产欧美官网在线看,高校回应聋哑女生因长相完美被质疑

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

.NET 的全新低延時(shí)高吞吐自適應(yīng) GC - Satori GC

freeflydom
2025年6月3日 10:40 本文熱度 236

GC 的 STW 問(wèn)題#

GC,垃圾回收器,本質(zhì)上是一種能夠自動(dòng)管理自己分配的內(nèi)存的生命周期的內(nèi)存分配器。這種方法被大多數(shù)流行編程語(yǔ)言采用,然而當(dāng)你使用垃圾回收器時(shí),你會(huì)失去對(duì)應(yīng)用程序如何管理內(nèi)存的控制。C# 允許在自動(dòng)控制內(nèi)存的基礎(chǔ)之上局部對(duì)內(nèi)存進(jìn)行手動(dòng)控制,但是自動(dòng)控制仍然是主要的場(chǎng)景。

然而 GC 總是需要暫停程序的運(yùn)行以遍歷和識(shí)別存活的對(duì)象,從而刪除無(wú)效對(duì)象以及進(jìn)行維護(hù)操作(例如通過(guò)移動(dòng)對(duì)象到更緊湊的內(nèi)存區(qū)域以減少內(nèi)存碎片,這個(gè)過(guò)程也叫做壓縮)。GC 暫停整個(gè)程序的行為也叫做 STW(Stop-The-World)。這個(gè)暫停時(shí)間越長(zhǎng),對(duì)應(yīng)用的影響越大。

長(zhǎng)期以來(lái),.NET 的 GC 都一直在朝著優(yōu)化吞吐量性能和內(nèi)存占用的方向不斷優(yōu)化,這對(duì)于 Web 應(yīng)用以及跑在容器中的服務(wù)而言非常適合。而在客戶端、游戲和金融領(lǐng)域,開(kāi)發(fā)人員一直都需要格外注意代碼中的分配問(wèn)題,例如使用對(duì)象池、值類型以及非托管內(nèi)存等等,避免產(chǎn)生大量的垃圾和各種 GC 難以處理的反模式,以此來(lái)減少 GC 的單次暫停時(shí)間。例如在游戲中,要做到 60fps,留給每一幀的時(shí)間只有 16ms,這其中如果 GC 單次暫停時(shí)間過(guò)長(zhǎng),用戶就會(huì)觀察到明顯的掉幀。

Workstation GC?Server GC?DATAS GC?#

.NET 一直以來(lái)都有兩種 GC 模式 —— Workstation GC 和 Server GC。

Workstation GC 是 .NET 最古老的 GC 模式,其目標(biāo)之一是最小化內(nèi)存占用,以適配資源有限的場(chǎng)景。在 Workstation GC 中,它只會(huì)利用你一個(gè) CPU 核心,因此哪怕你有多核的計(jì)算資源,Workstation GC 也不會(huì)去使用它們來(lái)優(yōu)化分配性能,雖然 Workstation GC 同樣支持后臺(tái)回收,但即使開(kāi)啟后臺(tái)回收,Workstation GC 也之多只會(huì)用一個(gè)后臺(tái)線程。這么一來(lái)其性能發(fā)揮就會(huì)受到不小的限制。面對(duì)大量分配和大量回收?qǐng)鼍皶r(shí) Workstation GC 則顯得力不從心。不過(guò),當(dāng)你的應(yīng)用很輕量并且不怎么分配內(nèi)存的時(shí)候,Workstation GC 將是一個(gè)很適合的選擇。

而之后誕生的 Server GC 則可以有效的利用多核計(jì)算資源,根據(jù) CPU 核心數(shù)量來(lái)控制托管堆數(shù)量,大幅度提升了吞吐量。然而 Server GC 的缺點(diǎn)也很明顯——內(nèi)存占用大。另外,Server GC 雖然通過(guò)并發(fā) GC 等方式將一部分工作移動(dòng)到 STW 之外,從而使得 GC 和應(yīng)用程序可以同時(shí)運(yùn)行,讓 STW 得到了不小的改進(jìn),然而 Server GC 的暫停時(shí)間仍然稱不上優(yōu)秀,雖然在 Web 服務(wù)等應(yīng)用場(chǎng)景下表現(xiàn)得不錯(cuò),然而在一些極端情況下則可能需要暫停上百毫秒。

為了進(jìn)一步改善 Server GC 的綜合表現(xiàn),.NET 9 引入了新的 DATAS GC,試圖在優(yōu)化內(nèi)存占用的同時(shí)提升暫停時(shí)間表現(xiàn)。這個(gè) GC 通過(guò)引入各種啟發(fā)算法自適應(yīng)應(yīng)用場(chǎng)景來(lái)最小化內(nèi)存占用的同時(shí),也改善了暫停時(shí)間。測(cè)試表明 DATAS GC 相比 Server GC 雖然犧牲了個(gè)位數(shù)百分比的吞吐量性能,卻成功的減少了 70%~90% 的內(nèi)存占用的同時(shí),暫停時(shí)間也縮減到 Server GC 的 1/3。

然而,這仍然不能算是完美的解決方案。開(kāi)發(fā)者們都是抱著既要又要還要的心理,需要的是一個(gè)既能做到大吞吐量,暫停時(shí)間又短,同時(shí)內(nèi)存占用還小的 GC。

因此,.NET 全新的 GC —— 在 .NET Runtime 核心成員幾年的努力下誕生了!這就是接下來(lái)我要講的 Satori GC。

Satori GC

為了讓 GC 能夠正確追蹤對(duì)象,在不少語(yǔ)言中,編譯器會(huì)給存儲(chǔ)操作插入一個(gè)寫(xiě)屏障。在寫(xiě)屏障中 GC 會(huì)更新對(duì)象的引用從而確保每一個(gè)對(duì)象都能夠正確被追蹤。這么做的好處很明顯,相比讀操作而言,寫(xiě)操作更少,將屏障分擔(dān)到每次的寫(xiě)操作里顯然是一個(gè)更有效率的方法。然而這么做的壞處也很明顯:當(dāng) GC 需要執(zhí)行壓縮操作時(shí)不得不暫停整個(gè)程序,避免代碼訪問(wèn)到無(wú)效的內(nèi)存地址。

而 JVM 上的一些低延時(shí) GC 則放棄了寫(xiě)屏障,轉(zhuǎn)而使用讀屏障,在每次讀取內(nèi)存地址的時(shí)候通過(guò)插入屏障來(lái)確保始終拿到的是最新的內(nèi)存地址,來(lái)避免無(wú)效地址訪問(wèn)。然而讀操作在應(yīng)用中非常頻繁,這么做雖然能夠使得 GC 執(zhí)行壓縮操作時(shí)不再需要暫停整個(gè)程序,卻會(huì)不可避免地帶來(lái)性能的損失。

GC 執(zhí)行壓縮操作雖然開(kāi)銷(xiāo)很大,但相對(duì)于釋放操作而言只是少數(shù),為了少數(shù)的操作能夠并發(fā)執(zhí)行拖慢所有的讀操作顯得有些得不償失。另外,在 .NET 上,由于 .NET 支持內(nèi)部指針和固定對(duì)象的內(nèi)存地址,因此讀屏障在 .NET 上實(shí)現(xiàn)較為困難,并且會(huì)帶來(lái)吞吐量的嚴(yán)重下降,在許多場(chǎng)景下難以接受。

.NET 的新低延時(shí)高吞吐自適應(yīng) GC —— Satori GC 仍然采用 Dijkstra 風(fēng)格的寫(xiě)屏障設(shè)計(jì),因此吞吐量性能仍然能夠匹敵已有的 Server GC。

另外,Satori GC 采用了分代、增量并發(fā)回收設(shè)計(jì),所有與堆大小成比例的主要 GC 階段都會(huì)與應(yīng)用程序線程并發(fā)執(zhí)行,完全不需要暫停應(yīng)用程序,除了壓縮過(guò)程之外。不過(guò),壓縮僅僅是 GC 可以執(zhí)行但不是必須執(zhí)行的一個(gè)可選項(xiàng)。例如 C++/Rust 的內(nèi)存分配器也不會(huì)進(jìn)行壓縮,但仍能正常運(yùn)行;Go 的 GC 也不會(huì)進(jìn)行壓縮。

除了標(biāo)準(zhǔn)模式之外,Satori GC 還提供了低延時(shí)模式。在這個(gè)模式下 Satori GC 直接關(guān)閉了壓縮功能,通過(guò)犧牲少量的內(nèi)存占用來(lái)獲取更低的延時(shí)。在某些情況下,因?yàn)槔厥瞻l(fā)生得更快,或者壓縮本身并沒(méi)有帶來(lái)太多實(shí)際收益,內(nèi)存占用反而會(huì)變得更小。例如在一些 Web 場(chǎng)景,大量對(duì)象只存活在單次請(qǐng)求期間,然后很快就會(huì)被清除。既然這些對(duì)象很快都會(huì)變成垃圾,那為什么要進(jìn)行壓縮呢?

與 Go 的徹底不進(jìn)行壓縮的 GC 不同,Satori GC 可以在運(yùn)行時(shí)動(dòng)態(tài)切換壓縮的開(kāi)關(guān)狀態(tài),以適應(yīng)不同的應(yīng)用場(chǎng)景。想要開(kāi)啟低延時(shí)模式,只需要執(zhí)行 GCSettings.LatencyMode = GCLatencyMode.LowLatency 即可。在需要極低延時(shí)的場(chǎng)景(例如高幀率游戲或金融實(shí)時(shí)交易系統(tǒng))中,這一設(shè)置可以有效減少 GC 暫停時(shí)間。

Satori GC 還允許開(kāi)發(fā)者根據(jù)需要關(guān)閉 Gen 0:畢竟不是所有的場(chǎng)景/應(yīng)用都能從 Gen 0 中獲益。當(dāng)應(yīng)用程序并不怎么用到 Gen 0 時(shí),為了支持 Gen 0 在寫(xiě)屏障中做的額外操作反而會(huì)拖慢性能。目前可以通過(guò)設(shè)置環(huán)境變量 DOTNET_gcGen0=0 來(lái)關(guān)閉 Gen 0,不過(guò)在 Satori GC 計(jì)劃中,將會(huì)實(shí)現(xiàn)根據(jù)實(shí)際應(yīng)用場(chǎng)景自動(dòng)決策 Gen 0 的開(kāi)啟與關(guān)閉。

性能測(cè)試

說(shuō)了這么多,新的 Satori GC 到底療效如何呢?讓我們擺出來(lái)性能測(cè)試來(lái)看看。

首先要說(shuō)的是,測(cè)試前需要設(shè)置 <TieredCompilation>false</TieredCompilation> 關(guān)閉分層編譯,因?yàn)?tier-0 的未優(yōu)化代碼會(huì)影響對(duì)象的生命周期,從而影響 GC 行為。

測(cè)試場(chǎng)景 1

Unity 有一個(gè) GC 壓力測(cè)試,游戲在每次更新都需要渲染出一幀畫(huà)面,而這個(gè)測(cè)試則模擬了游戲在每幀中分配大量的數(shù)據(jù),但是卻不渲染任何的內(nèi)容,從而通過(guò)單幀時(shí)間來(lái)反映 GC 的實(shí)際暫停。

代碼如下:

Copy
class Program {    const int kLinkedListSize = 1000;    const int kNumLinkedLists = 10000;    const int kNumLinkedListsToChangeEachFrame = 10;    private const int kNumFrames = 100000;    private static Random r = new Random();    class ReferenceContainer    {        public ReferenceContainer rf;    }    static ReferenceContainer MakeLinkedList()    {        ReferenceContainer rf = null;        for (int i = 0; i < kLinkedListSize; i++)        {            ReferenceContainer link = new ReferenceContainer();            link.rf = rf;            rf = link;        }        return rf;    }    static ReferenceContainer[] refs = new ReferenceContainer[kNumLinkedLists];    static void UpdateLinkedLists(int numUpdated)    {        for (int i = 0; i < numUpdated; i++)        {            refs[r.Next(kNumLinkedLists)] = MakeLinkedList();        }    }    static void Main(string[] args)    {        GCSettings.LatencyMode = GCLatencyMode.LowLatency;                float maxMs = 0;        UpdateLinkedLists(kNumLinkedLists);        Stopwatch totalStopWatch = new Stopwatch();        Stopwatch frameStopWatch = new Stopwatch();        totalStopWatch.Start();        for (int i = 0; i < kNumFrames; i++)        {            frameStopWatch.Start();            UpdateLinkedLists(kNumLinkedListsToChangeEachFrame);            frameStopWatch.Stop();            if (frameStopWatch.ElapsedMilliseconds > maxMs)                maxMs = frameStopWatch.ElapsedMilliseconds;            frameStopWatch.Reset();        }        totalStopWatch.Stop();                Console.WriteLine($"Max Frame: {maxMs}, Avg Frame: {(float)totalStopWatch.ElapsedMilliseconds/kNumFrames}");    } }

測(cè)試結(jié)果如下:

GC最大幀時(shí)間平均幀時(shí)間峰值內(nèi)存占用
Server GC323 ms0.049ms5071.906 MB
DATAS GC139 ms0.146ms1959.301 MB
Workstation GC23 ms0.563 ms563.363 MB
Satori GC26 ms0.061 ms1449.582 MB
Satori GC (低延時(shí))8 ms0.050 ms1540.891 MB
Satori GC (低延時(shí),關(guān) Gen 0)3 ms0.042 ms1566.848 MB

可以看到 Satori GC 在擁有 Server GC 的吞吐量性能同時(shí)(平均幀時(shí)間),還擁有著優(yōu)秀的最大暫停時(shí)間(最大幀時(shí)間)。

測(cè)試場(chǎng)景 2

在這個(gè)測(cè)試中,代碼中將產(chǎn)生大量的 Gen 2 -> Gen 0 的反向引用讓 GC 變得非常繁忙,然后通過(guò)大量分配生命周期很短的臨時(shí)對(duì)象觸發(fā)大量的 Gen 0 GC。

Copy
using System.Diagnostics; using System.Runtime; using System.Runtime.CompilerServices; object[] a = new object[100_000_000]; var sw = Stopwatch.StartNew(); var sw2 = Stopwatch.StartNew(); var count = GC.CollectionCount(0) + GC.CollectionCount(1) + GC.CollectionCount(2); for (var iter = 0; ; iter++) {    // Create a lot of Gen2 -> Gen0 references to keep the GC busy    object o = new object();    for (int i = 0; i < a.Length; i++)    {        a[i] = o;    }    sw.Restart();    // Use the object to keep it alive    Use(a, o);    // Create a lot of short lived objects to trigger Gen0 GC    for (int i = 0; i < 1000; i++)    {        GC.KeepAlive(new string('a', 10000));    }    var newCount = GC.CollectionCount(0) + GC.CollectionCount(1) + GC.CollectionCount(2);    if (newCount != count)    {        Console.WriteLine($"Gen0: {GC.CollectionCount(0)}, Gen1: {GC.CollectionCount(1)}, Gen2: {GC.CollectionCount(2)}, Pause on Gen0: {sw.ElapsedMilliseconds}ms, Throughput: {(iter + 1) / sw2.Elapsed.TotalSeconds} iters/sec, Max Working Set: {Process.GetCurrentProcess().PeakWorkingSet64 / 1048576.0} MB");        count = newCount;        iter = -1;        sw2.Restart();    } } [MethodImpl(MethodImplOptions.NoInlining)] static void Use(object[] arr, object obj) { }

由于這個(gè)測(cè)試主要就是測(cè)試 Gen 0 的回收性能,因此測(cè)試結(jié)果中將不包含關(guān)閉 Gen 0 的情況。

GC單次暫停吞吐量峰值內(nèi)存占用
Server GC59 ms7.485 iter/s1286.898 MB
DATAS GC60 ms6.362 iter/s859.722 MB
Workstation GC1081 ms0.804 iter/s805.453 MB
Satori GC0 ms4.448 iter/s801.441 MB
Satori GC (低延時(shí))0 ms4.480 iter/s804.761 MB

這個(gè)測(cè)試中 Satori GC 表現(xiàn)得非常亮眼:擁有不錯(cuò)的吞吐量性能的同時(shí),做到了亞毫秒級(jí)別的暫停時(shí)間:可以說(shuō)在這個(gè)測(cè)試中 Satori GC 壓根就沒(méi)有暫停過(guò)我們的應(yīng)用程序!

測(cè)試場(chǎng)景 3

這次我們使用 BinaryTree Benchmark 進(jìn)行測(cè)試,這個(gè)測(cè)試由于會(huì)短時(shí)間大量分配對(duì)象,因此對(duì)于 GC 而言是一項(xiàng)壓力很大的測(cè)試。

Copy
using System.Diagnostics; using System.Diagnostics.Tracing; using System.Runtime; using System.Runtime.CompilerServices; using Microsoft.Diagnostics.NETCore.Client; using Microsoft.Diagnostics.Tracing; using Microsoft.Diagnostics.Tracing.Analysis; using Microsoft.Diagnostics.Tracing.Parsers; class Program {    [MethodImpl(MethodImplOptions.AggressiveOptimization)]    static void Main()    {        var pauses = new List<double>();        var client = new DiagnosticsClient(Environment.ProcessId);        EventPipeSession eventPipeSession = client.StartEventPipeSession([new("Microsoft-Windows-DotNETRuntime",            EventLevel.Informational, (long)ClrTraceEventParser.Keywords.GC)], false);        var source = new EventPipeEventSource(eventPipeSession.EventStream);        source.NeedLoadedDotNetRuntimes();        source.AddCallbackOnProcessStart(proc =>        {            proc.AddCallbackOnDotNetRuntimeLoad(runtime =>            {                runtime.GCEnd += (p, gc) =>                {                    if (p.ProcessID == Environment.ProcessId)                    {                        pauses.Add(gc.PauseDurationMSec);                    }                };            });        });        GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true);        GC.WaitForPendingFinalizers();        GC.WaitForFullGCComplete();        Thread.Sleep(5000);        new Thread(() => source.Process()).Start();        pauses.Clear();        Test(22);                source.StopProcessing();        Console.WriteLine($"Max GC Pause: {pauses.Max()}ms");        Console.WriteLine($"Average GC Pause: {pauses.Average()}ms");        pauses.Sort();        Console.WriteLine($"P99.9 GC Pause: {pauses.Take((int)(pauses.Count * 0.999)).Max()}ms");        Console.WriteLine($"P99 GC Pause: {pauses.Take((int)(pauses.Count * 0.99)).Max()}ms");        Console.WriteLine($"P95 GC Pause: {pauses.Take((int)(pauses.Count * 0.95)).Max()}ms");        Console.WriteLine($"P90 GC Pause: {pauses.Take((int)(pauses.Count * 0.9)).Max()}ms");        Console.WriteLine($"P80 GC Pause: {pauses.Take((int)(pauses.Count * 0.8)).Max()}ms");        using (var process = Process.GetCurrentProcess())        {            Console.WriteLine($"Peak WorkingSet: {process.PeakWorkingSet64} bytes");        }    }    static void Test(int size)    {        var bt = new BinaryTrees.Benchmarks();        var sw = Stopwatch.StartNew();        bt.ClassBinaryTree(size);        Console.WriteLine($"Elapsed: {sw.Elapsed.TotalMilliseconds}ms");    } } public class BinaryTrees {    class ClassTreeNode    {        class Next { public required ClassTreeNode left, right; }        readonly Next? next;        ClassTreeNode(ClassTreeNode left, ClassTreeNode right) =>            next = new Next { left = left, right = right };        public ClassTreeNode() { }        internal static ClassTreeNode Create(int d)        {            return d == 1 ? new ClassTreeNode(new ClassTreeNode(), new ClassTreeNode())                          : new ClassTreeNode(Create(d - 1), Create(d - 1));        }        internal int Check()        {            int c = 1;            var current = next;            while (current != null)            {                c += current.right.Check() + 1;                current = current.left.next;            }            return c;        }    }    public class Benchmarks    {        const int MinDepth = 4;        public int ClassBinaryTree(int maxDepth)        {            var longLivedTree = ClassTreeNode.Create(maxDepth);            var nResults = (maxDepth - MinDepth) / 2 + 1;            for (int i = 0; i < nResults; i++)            {                var depth = i * 2 + MinDepth;                var n = 1 << maxDepth - depth + MinDepth;                var check = 0;                for (int j = 0; j < n; j++)                {                    check += ClassTreeNode.Create(depth).Check();                }            }            return longLivedTree.Check();        }    } }

這一次我們使用 Microsoft.Diagnostics.NETCore.Client 來(lái)精準(zhǔn)的跟蹤每一次 GC 的暫停時(shí)間。

測(cè)試結(jié)果如下:

性能指標(biāo)Workstation GCServer GCDATAS GCSatori GCSatori GC (低延時(shí))Satori GC (關(guān) Gen 0)
執(zhí)行所要時(shí)間 (ms)63,611.395422,645.352524,881.611441,515.633340,642.300813528.3383
峰值內(nèi)存占用 (bytes)1,442,217,9844,314,828,8002,076,291,0721,734,955,0081,537,855,4881,541,136,384
最大暫停時(shí)間 (ms)48.9107259.9675197.72126.52394.09791.2347
平均暫停時(shí)間 (ms)6.11728238312.007850673.3040141640.6734356910.4377585530.1391
P99.9 暫停時(shí)間 (ms)46.8537243.2844172.32595.85353.68350.9887
P99 暫停時(shí)間 (ms)44.0532207.362757.46815.26613.20120.5814
P95 暫停時(shí)間 (ms)39.490348.72698.923.00541.38540.3536
P90 暫停時(shí)間 (ms)23.132721.45882.80131.78590.92040.2681
P80 暫停時(shí)間 (ms)8.33174.75771.75810.80090.60060.1942

這一次 Satori GC 的標(biāo)準(zhǔn)模式和低延時(shí)模式都做到了非常低的延時(shí),而關(guān)閉 Gen 0 后 Satori GC 更是直接衛(wèi)冕 GC 之王,不僅執(zhí)行性能上跑過(guò)了 Server GC,同時(shí)還做到了接近 Workstation GC 級(jí)別的內(nèi)存占用,并且還做到了亞毫秒級(jí)別的最大 STW 時(shí)間!

測(cè)試場(chǎng)景 4

這個(gè)場(chǎng)景來(lái)自社區(qū)貢獻(xiàn)的 GC 測(cè)試:https://github.com/alexyakunin/GCBurn

這個(gè)測(cè)試包含三個(gè)不同的重分配的測(cè)試項(xiàng)目,模擬三種場(chǎng)景:

  • Cache Server:使用一半的內(nèi)存(大約 16G),分配大約 1.86 億個(gè)對(duì)象
  • Stateless Server:一個(gè)無(wú)狀態(tài) Web Server
  • Worker Server:一個(gè)有狀態(tài)的 Worker 始終占據(jù) 20% 內(nèi)存(大約 6G),分配大概 7400 萬(wàn)個(gè)對(duì)象

測(cè)試結(jié)果由其他社區(qū)成員提供。

首先看分配速率:

Server GC 是針對(duì)吞吐量進(jìn)行大量?jī)?yōu)化的,因此做到最高的吞吐量性能并不意外。Satori GC 在 Cache Server 場(chǎng)景有所落后,但是現(xiàn)實(shí)中并不會(huì)有在一秒內(nèi)分配超過(guò) 2 千萬(wàn)個(gè)對(duì)象的場(chǎng)景,因此這個(gè)性能水平并不會(huì)造成實(shí)際的性能瓶頸。

然后看暫停時(shí)間:

注意時(shí)間的單位是微秒(0.001ms),并且縱坐標(biāo)進(jìn)行了對(duì)數(shù)縮放。Satori GC 成功地做到了亞毫秒(小于 1000 微秒)級(jí)別的暫停。

最后看峰值內(nèi)存占用:

可以看到 Satori GC 相比其他 GC 而言有著出色的內(nèi)存占用,在所有測(cè)試結(jié)果中幾乎都是那個(gè)內(nèi)存占用最低的。

綜合以上三點(diǎn),我們可以看到 Satori GC 在犧牲少量的吞吐量性能的同時(shí),做到了亞毫秒級(jí)別的延時(shí)和低內(nèi)存占用。只能說(shuō):干得漂亮!

大量分配速率測(cè)試

這同樣是來(lái)自其他社區(qū)成員貢獻(xiàn)的測(cè)試結(jié)果。在這個(gè)測(cè)試中,代碼使用一個(gè)循環(huán)在所有的線程上大量分配對(duì)象并立馬釋放。

測(cè)試結(jié)果如下:

可以看到 Satori GC 的默認(rèn)模式在這個(gè)測(cè)試中做到了最好的分配吞吐量性能,成功做到每秒分配 20 億個(gè)對(duì)象。

總結(jié)

Satori GC 的目標(biāo)是為 .NET 帶來(lái)了一種全新的低延時(shí)高吞吐自適應(yīng) GC,不僅有著優(yōu)秀的分配速率,同時(shí)還能做到亞毫秒級(jí)別的暫停時(shí)間和低內(nèi)存占用,與此同時(shí)做到 0 配置開(kāi)箱即用。

目前 Satori GC 仍然處于實(shí)驗(yàn)性階段,還有不少的課題需要解決,例如運(yùn)行時(shí)自動(dòng)決策 Gen 0 的開(kāi)關(guān)、更好的策略以均衡吞吐量性能和內(nèi)存占用以及適配更新版本的 .NET 等等,但是已經(jīng)可以用于真實(shí)世界應(yīng)用了,想要試用 Satori GC 的話可以參考下面的方法在自己的應(yīng)用中啟用。

osu! 作為一款從引擎到游戲客戶端都是純 C# 開(kāi)發(fā)的游戲,已經(jīng)開(kāi)始提供使用 Satori GC 的選項(xiàng)。在選歌列表的滾動(dòng)測(cè)試中,Satori GC 成功將幀數(shù)翻了一倍,從現(xiàn)在的 120 fps 左右提升到接近 300 fps。

相信等 Satori GC 成熟正式作為 .NET 默認(rèn) GC 啟用后,將會(huì)為 .NET 帶來(lái)大量的性能提升,并擴(kuò)展到更多的應(yīng)用場(chǎng)景。

啟用方法

截至目前(2025/5/22),Satori GC 僅支持在 .NET 8 應(yīng)用中啟用。考慮到這是目前最新的 LTS 穩(wěn)定版本,因此目前來(lái)看也足夠了,另外 Satori GC 的開(kāi)發(fā)人員已經(jīng)在著手適配 .NET 9。

osu! 團(tuán)隊(duì)配置了 CI 自動(dòng)構(gòu)建最新的 Satori GC,因此我們不需要手動(dòng)構(gòu)建 .NET Runtime 源碼得到 GC,直接下載對(duì)應(yīng)的二進(jìn)制即可使用。

對(duì)于 .NET 8 應(yīng)用:

  1. 使用 dotnet publish -c Release -r <rid> --self-contained 發(fā)布一個(gè)自包含應(yīng)用,例如 dotnet publish -c Release -r win-x64 --self-contained
  2. 從 https://github.com/ppy/Satori/releases 下載對(duì)應(yīng)平臺(tái)的最新 Satori GC 構(gòu)建,例如 win-x64.zip
  3. 解壓得到三個(gè)文件:如果是 Windows 平臺(tái)就是 coreclr.dllclrjit.dll 和 System.Private.CoreLib.dll;而如果是 Linux 則是 libcoreclr.so、libclrjit.so 和 System.Private.CoreLib.dll
  4. 找到第一步發(fā)布出來(lái)的應(yīng)用(一般在 bin/Release/net8.0/<rid>/publish 文件夾里,例如 bin/Release/net8.0/win-x64/publish),用第三步得到的三個(gè)文件替換掉發(fā)布目錄里面的同名文件

然后即可享受 Satori GC 帶來(lái)的低延時(shí)體驗(yàn)。

反饋渠道

如果在使用過(guò)程中遇到了任何問(wèn)題,可以參考:

轉(zhuǎn)自https://www.cnblogs.com/hez2010/p/18889954/


該文章在 2025/6/3 10:41:46 編輯過(guò)
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車(chē)隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷(xiāo)售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved