日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

从CLR GC到CoreCLR GC看.NET Core对云原生的支持

發(fā)布時(shí)間:2023/12/4 asp.net 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从CLR GC到CoreCLR GC看.NET Core对云原生的支持 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

內(nèi)存分配概要

前段時(shí)間在園子里看到有人提到了GC學(xué)習(xí)的重要性,很贊同他的觀點(diǎn)。充分了解GC可以幫助我們更好的認(rèn)識(shí).NET的設(shè)計(jì)以及為何在云原生開發(fā)中.NET Core會(huì)占有更大的優(yōu)勢(shì),這也是一個(gè)程序員成長到更高層次所需要經(jīng)歷的過程。在認(rèn)識(shí)GC的過程中,我們先看一下.NET中內(nèi)存分配的概要知識(shí)。
.NET分配內(nèi)存,主要依據(jù)托管資源和非托管資源進(jìn)行分配。托管資源分配到了托管堆中并受CLR的管理,非托管資源分配到了非托管堆中。該節(jié)主要討論托管資源的分配。
CLR支持兩種基本類型:值類型和引用類型。CLR對(duì)這兩種類型在運(yùn)行時(shí)有兩種分配方式:

內(nèi)存的分配過程如下圖所示

需要注意的是,CLR還要維護(hù)一個(gè)指針,稱為NextObjPtr,這個(gè)指針指向下一個(gè)對(duì)象再堆中的分配位置。初始化時(shí),NextObjPtr設(shè)為地址空間區(qū)域的基地址。一個(gè)區(qū)域被非垃圾對(duì)象填滿后,CLR會(huì)分配更多的區(qū)域,指針也會(huì)不斷偏移。new操作符會(huì)返回對(duì)象的引用,就在返回這個(gè)引用之前,NextObjPtr指針的值會(huì)加上對(duì)象占用的字節(jié)數(shù)來得到一個(gè)新值,即下一個(gè)對(duì)象放入托管堆時(shí)的地址。

垃圾回收算法與GC運(yùn)行機(jī)制

常用的垃圾回收算法主要有引用計(jì)數(shù)算法和引用跟蹤算法。引用計(jì)算有著明顯的缺陷,.NET使用的垃圾回收算法是引用跟蹤法。小記:關(guān)于垃圾回收算法,我記得有一個(gè)知識(shí)點(diǎn),在C#中如果出現(xiàn)了循環(huán)引用是否會(huì)導(dǎo)致內(nèi)存溢出?如果比較了解這兩種算法就會(huì)知道不會(huì)溢出。

GC Root

引用跟蹤算法,通過一系列GCRoot對(duì)象作為起始點(diǎn),從這些點(diǎn)開始向下搜索,搜索的路徑成為引用鏈,當(dāng)一個(gè)對(duì)象到GC沒有任何引用鏈,說明對(duì)象可以被回收。

GC Root可以類比樹來解釋

GC根節(jié)點(diǎn)存在于堆棧中,指向Teacher引用對(duì)象。它包含一個(gè)ArrayList訂單集合,由Teacher對(duì)象引用。集合本身也包含對(duì)其元素的引用,隨著搜索深度的增加,樹也不斷長大。

GC根節(jié)點(diǎn)的引用源來自

(1)、堆棧
(2)、全局或靜態(tài)變量
(3)、CPU寄存器
(4)、互操作引用(COM / API調(diào)用中使用的.NET對(duì)象)
(5)、對(duì)象終結(jié)引用(objects finalization references)

GC運(yùn)行機(jī)制

GC引入了代的概念,分為三種代,G0、G1、G2,G0對(duì)象生存周期較短,越往后生存周期越長(雖然G2中由于直接存儲(chǔ)了大對(duì)象,又由于G2不是每次都會(huì)掃描,所以大多數(shù)情況下,G2中的對(duì)象的生存周期比G0中的更長)。

GC運(yùn)行如下圖所示

需要注意的是,CLR想要進(jìn)行垃圾回收時(shí),會(huì)立即掛起執(zhí)行托管代碼中的所有線程,正在執(zhí)行非托管代碼的線程不會(huì)掛起。所以再多線程環(huán)境下,可能會(huì)出現(xiàn)莫名其妙的詭異問題。

下圖為GC的整體運(yùn)行流程,包含五個(gè)步驟:

垃圾回收時(shí)機(jī)與模式

CLR會(huì)在一下情況發(fā)生時(shí),執(zhí)行GC操作

????? 1、當(dāng)GC的代的預(yù)算大小已經(jīng)達(dá)到閾值而無法對(duì)新對(duì)象分配空間的時(shí)候,比如GC的第0代已滿;

  2、顯式調(diào)用System.GC.Collect()(顯示調(diào)用要慎重,因?yàn)槭謩?dòng)調(diào)用可能會(huì)與自動(dòng)執(zhí)行的GC沖突,從而導(dǎo)致無法預(yù)知的問題);

  3、其他特殊情況,比如,操作系統(tǒng)內(nèi)存不足、CLR卸載AppDomain、CLR關(guān)閉,甚至某些極端情況下系統(tǒng)參數(shù)設(shè)置改變也可能導(dǎo)致GC回收。

關(guān)于GC模式主要有

  • WorkStation GC
  • Server GC
  • Concurrent GC
  • Non-Concurrent GC
  • Background GC

詳細(xì)信息請(qǐng)參閱:https://www.cnblogs.com/dacc123/p/10980718.html,這篇文章關(guān)于GC模式的說明比較詳細(xì)。

.NET Core 3.0的GC處理

.NET Core 3.0默認(rèn)更好的支持Docker資源限制,官方團(tuán)隊(duì)也在努力讓.NET Core成為真正的容器運(yùn)行時(shí),使其在低內(nèi)存環(huán)境中具有容器感知功能并高效運(yùn)行。

GC堆限制

.NET Core減少了CoreCLR默認(rèn)使用的內(nèi)存,如G0代內(nèi)存分配預(yù)算,以更好地與現(xiàn)代處理器緩存大小和緩存層次結(jié)構(gòu)保持一致。

在新的創(chuàng)建的GC堆數(shù)量的策略里,GC保留了一個(gè)內(nèi)存片段,每個(gè)堆最小是16M,在低內(nèi)存限制的機(jī)器上也可以很好的運(yùn)行。在多核CPU的機(jī)器上運(yùn)行時(shí),系統(tǒng)并沒有設(shè)置CPU的核數(shù)限制。例如,如果在48核計(jì)算機(jī)上設(shè)置160 MB內(nèi)存限制,則不需要?jiǎng)?chuàng)建48個(gè)GC堆。也就是說如果設(shè)置160 MB限制,則只會(huì)創(chuàng)建10個(gè)GC堆。如果未設(shè)置CPU限制,應(yīng)用程序可以利用計(jì)算機(jī)上的所有核心。

有了這樣的新策略,可以不需要啟用Docker環(huán)境下的.NET Core應(yīng)用的工作站GC的工作負(fù)載。

支持Docker內(nèi)存限制

Docker資源限制建立在cgroup之上,而cgroup是Linux的內(nèi)核功能。從運(yùn)行時(shí)的角度來看,我們需要定位cgroup原語。

設(shè)置cgroup限制時(shí)的.NET Core 3.0內(nèi)存使用規(guī)則:

  • 默認(rèn)GC堆大小:容器上cgroup內(nèi)存限制的最大值20MB或最大值的75%

  • 每個(gè)GC堆的最小保留段大小16MB,這將減少在具有大量?jī)?nèi)核和小內(nèi)存限制的計(jì)算機(jī)上創(chuàng)建的堆數(shù)

為了支持容器方案,添加了2個(gè)HardLimit配置:

  • GCHeapHardLimit - 指定GC堆的硬限制

  • GCHeapHardLimitPercent - 指定允許此進(jìn)程使用的物理內(nèi)存的百分比

如果同時(shí)指定了兩者,則首先檢查GCHeapHardLimit,并且只有在未指定GCHeapHardLimit時(shí)才檢查GCHeapHardLimitPercent。

如果兩者都未指定,但進(jìn)程正在有內(nèi)存限制的容器中運(yùn)行,則默認(rèn)是使用如下設(shè)置:

max(20mb,容器內(nèi)存限制的75%)

如果指定了hardlimit配置,并且程序在有內(nèi)存限制的容器中使用,GC堆的使用不會(huì)超過hardlimit限制,但總內(nèi)存仍然受容器的內(nèi)存限制。所以當(dāng)我們統(tǒng)計(jì)內(nèi)存消耗時(shí),基于容器內(nèi)存限制得出的數(shù)據(jù)。

舉例:

進(jìn)程在設(shè)置了200MB限制的容器中運(yùn)行,用戶還將GCHeapHardLimit配置為100MB。

如果把GC限制中100MB限制中的50MB用于GC,而容器限制中剩余的100MB用于其他用途,那么內(nèi)存消耗即為(50+100)/200=75%。

GC將更積極地執(zhí)行資源回收與釋放,因?yàn)镚C堆越接近GCHeapHardLimit限制,就越能實(shí)現(xiàn)提供更多可用內(nèi)存的目標(biāo),也越能使得應(yīng)用程序可以繼續(xù)而又安全地運(yùn)行。如果算法計(jì)算出的結(jié)果認(rèn)為此時(shí)的GC效率低下,那么將避免持續(xù)執(zhí)行完全阻塞的GC。

即使GC堆完全壓縮,GC依然會(huì)拋出一個(gè)OutOfMemoryException異常出來,這是因?yàn)樗峙涞亩汛笮〕^了GCHeapHardLimit的限制。

由此可見,.NET Core 3.0的設(shè)計(jì)是要穩(wěn)定運(yùn)行于有資源限制的容器中。

支持DockerCPU限制

在CPU限制的情況下,Docker上設(shè)置的值將向上舍入為下一個(gè)整數(shù)值。此值是CoreCLR使用的最大有效CPU核數(shù)。

默認(rèn)情況下,ASP.NET Core應(yīng)用程序啟用了服務(wù)器GC(它不適用于控制臺(tái)應(yīng)用程序),因?yàn)樗梢詫?shí)現(xiàn)高吞吐量并減少跨核心的爭(zhēng)用。當(dāng)進(jìn)程僅限于單個(gè)處理器時(shí),運(yùn)行時(shí)會(huì)自動(dòng)切換到工作站GC。即使您明確指定使用服務(wù)器GC,工作站GC也將始終用于單核環(huán)境。

通過計(jì)算CPU繁忙時(shí)間,設(shè)置CPU限制,我們避免了線程池的各種推導(dǎo)性競(jìng)爭(zhēng):

  • 嘗試分配更多的線程以增加CPU繁忙時(shí)間

  • 嘗試分配更少的線程,因?yàn)樘砑痈嗟木€程不會(huì)提高吞吐量

參考資料:

https://devblogs.microsoft.com/dotnet/using-net-and-docker-together-dockercon-2019-update/

https://github.com/dotnet/designs/blob/master/accepted/support-for-memory-limits.md

https://www.cnblogs.com/dacc123/p/10980718.html

https://blog.csdn.net/koudaidai/article/details/7794793

總結(jié)

以上是生活随笔為你收集整理的从CLR GC到CoreCLR GC看.NET Core对云原生的支持的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。