操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    起《英雄聯(lián)盟》這款游戲,相信大家一定都不會(huì)陌生。作為當(dāng)下最熱門的網(wǎng)游之一,《英雄聯(lián)盟》不僅擁有極為優(yōu)秀的游戲體驗(yàn),同時(shí)游戲?qū)﹄娔X的硬件配置要求并不高,幾乎大部分的臺(tái)式機(jī)或筆記本電腦都可以流暢運(yùn)行,深得玩家們的喜愛。

    不過,隨著電腦系統(tǒng)版本、硬件驅(qū)動(dòng)版本以及游戲版本的不斷更新,部分玩家即便是在配置較高的獨(dú)顯游戲本上運(yùn)行《英雄聯(lián)盟》這款游戲,也會(huì)遇到莫名其妙的卡頓掉幀情況。這對(duì)于不熟悉部分電腦軟硬件技術(shù)的游戲本玩家來說,無疑會(huì)顯得十分煩惱。

    為此,今天小編將給大家分享下自己對(duì)《英雄聯(lián)盟》這款游戲卡頓問題的分析與解決流程,希望相關(guān)經(jīng)驗(yàn)可以幫到更多的同遭遇玩家。

    在解決游戲卡頓問題之前,我們需要先通過簡(jiǎn)單的游戲信息,得出導(dǎo)致游戲卡頓的主要原因。

    運(yùn)行《英雄聯(lián)盟》游戲的過程中,按擊Ctrl+F組合鍵可以喚出FPS值監(jiān)控,通過對(duì)游戲右上角的FPS值與ms值大小,我們可以快速定位到卡頓原因。

    一般來說,要想流暢運(yùn)行《英雄聯(lián)盟》,F(xiàn)PS值需要大于60,ms值則是需要低于100ms。

    如果FPS值低于60,畫面會(huì)出現(xiàn)拖影、撕裂等問題,讓人產(chǎn)生卡頓感;

    如果ms值高過100,畫面則會(huì)出現(xiàn)技能延遲、人物漂移的問題,讓人產(chǎn)生卡頓感。

    首先簡(jiǎn)單說下網(wǎng)絡(luò)PING值過高的解決方案:

    方案一:檢查網(wǎng)絡(luò)環(huán)境,排除是否存在其他人蹭網(wǎng)的可能性。主要特征:網(wǎng)速時(shí)快時(shí)慢

    方案二:嘗試網(wǎng)絡(luò)加速、優(yōu)化軟件功能,這里建議使用騰訊自家的WEGAME軟件,可以直接顯示優(yōu)化效果,方便快捷。

    方案三:更換網(wǎng)絡(luò)連接,部分寬帶的網(wǎng)絡(luò)環(huán)境十分不穩(wěn)定,不適合網(wǎng)絡(luò)游戲的流暢加載。也可以試試手機(jī)熱點(diǎn),一般電信4G網(wǎng)絡(luò)玩《英雄聯(lián)盟》會(huì)比較穩(wěn)定,就是流量會(huì)消耗得比較快,需要注意控制。


    下面詳細(xì)說下FPS幀數(shù)較低的解決方案:

    需要了解的是,導(dǎo)致《英雄聯(lián)盟》游戲FPS值降低的原因是比較多的。但常見的影響原因還是以“CPU頻率低”、“顯卡頻率低”、“內(nèi)存占用高”三種情況為主。

    對(duì)于一名普通的電腦新手來說,要分析出這三個(gè)硬件具體的運(yùn)行問題還是比較困難的,所以這里小編建議大家可以提前安裝一個(gè)監(jiān)控軟件:《游戲加加》。

    通過《游戲加加》軟件對(duì)游戲運(yùn)行時(shí)的數(shù)據(jù)監(jiān)控,我們將能在游戲中實(shí)時(shí)看到CPU、顯卡、內(nèi)存的各項(xiàng)運(yùn)行數(shù)據(jù),方便我們快速定位游戲卡頓的原因是CPU還是顯卡或內(nèi)存。

    詳細(xì)設(shè)置可以參考下圖:

    CPU數(shù)據(jù)方面,我們需要留意頻率MHz值與溫度值的變化。(其實(shí)主要是看MHz值變化,但溫度過高普遍會(huì)是導(dǎo)致MHz值下降的主要因素)。

    CPU相關(guān)問題1:CPU溫度正常,但CPU的頻率MHz值等于或低于CPU主頻

    原因分析:電源未連接、性能模式設(shè)置為節(jié)能,限制了CPU性能發(fā)揮

    解決方案:連接電源,右擊桌面右下角電池圖標(biāo),進(jìn)入windows移動(dòng)中心,將電池模式改選為高性能。

    需要注意的是,部分游戲本型號(hào)還設(shè)置有獨(dú)立的性能按鍵、性能管理功能支持,需要留意這些功能不要設(shè)置為節(jié)能方案。

    CPU相關(guān)問題2:CPU溫度高于90°甚至接近100°,同時(shí)CPU的頻率MHz值也低于CPU型號(hào)的主頻

    原因分析:CPU散熱環(huán)境不佳,高溫導(dǎo)致頻率下降

    解決方案:用橡皮或瓶蓋墊高筆記本電腦與桌面的接觸面,讓機(jī)器有更好的散熱通風(fēng)環(huán)境。當(dāng)然,有相關(guān)散熱需求的玩家也可以考慮入手一款散熱支架設(shè)備,這樣本本的散熱效果會(huì)得到更明顯的變化。

    需要注意的是,對(duì)于部分已有幾年使用歷史的游戲本設(shè)備來說,電腦內(nèi)部的CPU是可能存在散熱硅脂硬化問題的,需要考慮進(jìn)行清灰、重上散熱硅脂等保養(yǎng)操作才能恢復(fù)正常散熱狀態(tài)。不會(huì)的玩家建議聯(lián)系售后或周邊電腦維修店咨詢下相關(guān)保養(yǎng)服務(wù)。

    顯卡方面,同樣也是需要留意頻率MHz值與溫度值的變化,但同時(shí)我們還需要留意一下顯存占用的相關(guān)信息。

    顯卡相關(guān)問題1:顯存為0% ,顯卡頻率非常低。

    原因分析:游戲以核顯方式運(yùn)行(獨(dú)顯運(yùn)行時(shí)會(huì)產(chǎn)生顯存占用,只有核顯運(yùn)行時(shí)是共享系統(tǒng)內(nèi)存作為顯存的,所以核顯運(yùn)行時(shí)顯存占用會(huì)顯示為0%)

    解決方案:使用NVIDIA 控制面板,將《英雄聯(lián)盟》的運(yùn)行進(jìn)程設(shè)置為:以高性能NVIDIA處理器運(yùn)行,并應(yīng)用保存。

    需要注意的是,《英雄聯(lián)盟》這款游戲的運(yùn)行進(jìn)程名為:league of legends Client

    顯卡相關(guān)問題2:顯存不為0,游戲幀數(shù)為固定值(幀數(shù)保持在39-40FPS左右或59-60FPS左右)

    原因分析:開啟了某項(xiàng)畫面鎖幀功能。

    解決方案:檢查游戲內(nèi)部設(shè)置以及NVIDIA Geforce Experience軟件的電池優(yōu)化設(shè)置:WHISPER MODE、BATTERY BOOST。

    顯卡相關(guān)問題3: 顯存不為0,顯卡溫度不高,但顯卡頻率MHz值與游戲幀數(shù)FPS值變化較大(例如顯卡頻率從1400MHz跳到700MHz,游戲幀數(shù)從100FPS跳到50FPS)

    原因分析:顯卡驅(qū)動(dòng)版本或游戲版本優(yōu)化出現(xiàn)問題

    解決方案:使用NVIDIA Geforce Experience軟件,更新或回退、重裝顯卡驅(qū)動(dòng)版本。如是游戲版本BUG問題,游戲官方一般會(huì)發(fā)布相關(guān)維護(hù)公告,耐心等待維護(hù)即可。

    需要注意的是,如果系統(tǒng)未安裝過NVIDIA Geforce Experience軟件,需要到NVIDIA驅(qū)動(dòng)程序官網(wǎng)下載驅(qū)動(dòng)或軟件。

    最后是內(nèi)存方面,而內(nèi)存占用的問題是比較統(tǒng)一的。只需要留意以下建議即可:

    《英雄聯(lián)盟》這款游戲建議選用8GB運(yùn)行內(nèi)存以上的電腦進(jìn)行運(yùn)行,如果您的游戲本內(nèi)存大于8GB,卻出現(xiàn)“內(nèi)存超過90%,幀數(shù)極其不穩(wěn)定”的情況。只需要考慮在進(jìn)入游戲前推出其他后臺(tái)軟件或加裝內(nèi)存條就可以改善了。


    以上內(nèi)容就是小編對(duì)《英雄聯(lián)盟》這款游戲的卡頓問題的相關(guān)解決教程與建議了,如你在使用游戲本的過程中也遇到本款游戲卡頓的,不妨可以參考借鑒下本篇的相關(guān)檢查、修復(fù)操作,希望能對(duì)同為玩家的你有所幫助。

    簡(jiǎn)介

    自定義固定內(nèi)存塊分配器用于解決兩種類型的內(nèi)存問題。第一,全局堆內(nèi)存的分配和釋放非常慢而且是不確定的。你不能確定內(nèi)存管理需要消耗多長(zhǎng)時(shí)間。第二,降低由堆內(nèi)存碎片(對(duì)于執(zhí)行關(guān)鍵操作的系統(tǒng)尤為重要)造成的內(nèi)存分配失敗的可能性。

    即使不是執(zhí)行關(guān)鍵操作的系統(tǒng),一些嵌入式系統(tǒng)也需要被設(shè)計(jì)成需要運(yùn)行數(shù)周甚至數(shù)年而不重啟。取決于內(nèi)存分配的模式和堆內(nèi)存的實(shí)現(xiàn)方式,長(zhǎng)時(shí)間的使用堆內(nèi)存可能導(dǎo)致堆內(nèi)存錯(cuò)誤。

    典型的解決方案是預(yù)先靜態(tài)聲明所有對(duì)象的內(nèi)存,從而擺脫動(dòng)態(tài)申請(qǐng)內(nèi)存。然而,由于對(duì)象即使沒有被使用,也已經(jīng)存在并占據(jù)一部分內(nèi)存,靜態(tài)分配內(nèi)存的方式會(huì)浪費(fèi)內(nèi)存存儲(chǔ)。此外,使用動(dòng)態(tài)內(nèi)存分配方式實(shí)現(xiàn)的系統(tǒng)提供更為自然的設(shè)計(jì)框架,而不像靜態(tài)內(nèi)存分配需要事先分配所有對(duì)象。

    固定內(nèi)存塊分配器并不是一種新的方法。人們已經(jīng)設(shè)計(jì)過多種自定義內(nèi)存分配器很長(zhǎng)時(shí)間了。這里,我提供的是我在很多項(xiàng)目中成功使用的,一種簡(jiǎn)單的C++內(nèi)存分配器的實(shí)現(xiàn)。

    這種分配器的實(shí)現(xiàn)具有如下特點(diǎn):

    • 比全局堆內(nèi)存速度快

    • 消除堆內(nèi)存碎片錯(cuò)誤

    • 不需要額外的內(nèi)存存儲(chǔ)(除了需要幾個(gè)字節(jié)的靜態(tài)內(nèi)存)

    • 易于使用

    • 代碼量很小

    這里將提供一個(gè)申請(qǐng)、釋放內(nèi)存的,包含上面所提到特點(diǎn)的簡(jiǎn)單類。

    閱讀完此文后,請(qǐng)同時(shí)閱讀Replace malloc/free with a Fast Fixed Block Memory Allocator,查看如何使用分配器Allocator替代CRT(C/C++ Runtime Library)。

    回收內(nèi)存存儲(chǔ)

    內(nèi)存管理模式的基本哲學(xué)是在對(duì)象內(nèi)存分配時(shí)能夠回收內(nèi)存。一旦在內(nèi)存中創(chuàng)建了一個(gè)對(duì)象,它所占用的內(nèi)存就不能被重新分配。同時(shí),內(nèi)存要能夠回收,允許相同類型的對(duì)象重用這部分內(nèi)存。我實(shí)現(xiàn)了一個(gè)名為Allocator的類來展示這些技巧。

    當(dāng)應(yīng)用程序使用Allocator類進(jìn)行刪除時(shí),對(duì)象占用的內(nèi)存空間被釋放以備重用,但卻不會(huì)立即釋放給內(nèi)存管理器,這些內(nèi)存保留在就一個(gè)稱之為“釋放列表”的鏈表中,并再次分配給相同類型的對(duì)象。對(duì)每個(gè)內(nèi)存分配的請(qǐng)求,Allocaor類首先檢查“釋放列表”中是否存在待釋放的內(nèi)存。只有“釋放列表”中沒有可用的內(nèi)存空間時(shí)才會(huì)分配新的內(nèi)存。根據(jù)所需的Allocator類的行為,內(nèi)存存儲(chǔ)以三種操作模式使用全局堆內(nèi)存或者靜態(tài)內(nèi)存池。

    • 1.堆內(nèi)存

    • 2.堆內(nèi)存池

    • 3.靜態(tài)內(nèi)存池

    堆內(nèi)存 vs. 內(nèi)存池

    Allocator類在“釋放列表”為空時(shí),能夠從堆內(nèi)存或者內(nèi)存池中申請(qǐng)新內(nèi)存。如果使用內(nèi)存池,你必須事先確定好對(duì)象的數(shù)量。確保內(nèi)存池足夠容納所有需要使用的對(duì)象。另一方面,使用堆內(nèi)存沒有數(shù)量大小的限制——可以構(gòu)造內(nèi)存允許的盡可能多的對(duì)象。

    堆內(nèi)存模式在全局堆內(nèi)存上為對(duì)象分配內(nèi)存。釋放操作將這塊內(nèi)存放入“釋放了列表”以備重用。當(dāng)“釋放列表”為空時(shí),需要在堆內(nèi)存上創(chuàng)建新內(nèi)存。這種方式提供了動(dòng)態(tài)內(nèi)存的分配和釋放,優(yōu)點(diǎn)是內(nèi)存塊可以在運(yùn)行時(shí)動(dòng)態(tài)增加,缺點(diǎn)是內(nèi)存塊創(chuàng)建期間是不確定的,可能創(chuàng)建失敗。

    堆內(nèi)存池模式從全局堆內(nèi)存創(chuàng)建一個(gè)內(nèi)存池。當(dāng)Allocator類對(duì)象創(chuàng)建時(shí),使用new操作符創(chuàng)建內(nèi)存池。然后使用內(nèi)存池中的內(nèi)存塊進(jìn)行內(nèi)存分配。

    靜態(tài)內(nèi)存池模式使用從靜態(tài)內(nèi)存中分配的內(nèi)存池。靜態(tài)內(nèi)存池由使用者進(jìn)行分配而不是由Allocator對(duì)象進(jìn)行創(chuàng)建。

    堆內(nèi)存池模式和靜態(tài)內(nèi)存池模式提供了內(nèi)存操作的連續(xù)使用,因?yàn)閮?nèi)存分配器不需要分配單獨(dú)的內(nèi)存塊。這樣分配內(nèi)存的過程是十分快速且具有確定性的。

    類設(shè)計(jì)

    類的接口很簡(jiǎn)單。Allocate()返回指向內(nèi)存塊的指針,Deallocate()釋放內(nèi)存以備重用。構(gòu)造函數(shù)需要設(shè)置對(duì)象的大小,并且如果使用內(nèi)存池,需要分配內(nèi)存池空間。

    類的構(gòu)造函數(shù)中的參數(shù)用于決定內(nèi)存塊分配的位置。size參數(shù)控制固定內(nèi)存塊的大小。objects參數(shù)設(shè)置申請(qǐng)內(nèi)存塊的個(gè)數(shù),其值為0表示從堆內(nèi)存中申請(qǐng)新內(nèi)存塊,非0表示使用內(nèi)存池方式(堆內(nèi)存池或者靜態(tài)內(nèi)存池)分配對(duì)象實(shí)例空間。memory參數(shù)是指向靜態(tài)內(nèi)存的指針。如果memory等于0并且objects非零,Allocator將從堆內(nèi)存中創(chuàng)建一個(gè)內(nèi)存池。靜態(tài)內(nèi)存池內(nèi)存大小必須是size*object字節(jié)。name參數(shù)為內(nèi)存分配器命名,用于收集分配器使用信息。

    class Allocator{public:

    下面的例子展示三種分配器模式中的構(gòu)造函數(shù)是如何賦值的。

    // Heap blocks mode with unlimited 100 byte blocksAllocator allocatorHeapBlocks(100);// Heap pool mode with 20, 100 byte blocksAllocator allocatorHeapPool(100, 20);// Static pool mode with 20, 100 byte blockschar staticMemoryPool[100 * 20];Allocator allocatorStaticPool(100, 20, staticMemoryPool);

    為了簡(jiǎn)化靜態(tài)內(nèi)存池方法,提供AllocatorPool<>模板類。模板的第一個(gè)參數(shù)設(shè)置申請(qǐng)內(nèi)存對(duì)象類型,第二個(gè)參數(shù)設(shè)置申請(qǐng)對(duì)象的數(shù)量。

    // Static pool mode with 20 MyClass sized blocks AllocatorPool<MyClass, 20> allocatorStaticPool2;

    Deallocate()將內(nèi)存地址放入“?!敝?。這個(gè)“?!钡膶?shí)現(xiàn)方式類似于單項(xiàng)鏈表(“釋放列表”),但是只能添加、移除頭部的對(duì)象,其行為類似棧的特性。使用“?!笔沟梅峙?、釋放操作更為快速,因?yàn)椴恍枰湵肀闅v而只需要壓入和彈出操作。

    void* memory1=allocatorHeapBlocks.Allocate(100);

    這樣便在不增加額外存儲(chǔ)的情況下,將內(nèi)存塊鏈接在“釋放列表”中。例如,當(dāng)我們使用全局operate new時(shí),首先申請(qǐng)內(nèi)存,然后調(diào)用構(gòu)造函數(shù)。delete的過程與此相反,首先調(diào)用析構(gòu)函數(shù),然后釋放掉內(nèi)存。調(diào)用完析構(gòu)函數(shù)后,在內(nèi)存釋放給堆之前,這塊內(nèi)存不再被原有的對(duì)象使用,而是放到“釋放列表”中以備重用。由于Allocator類需要保存已經(jīng)釋放的內(nèi)存塊,在使用delete操作符時(shí),我們將“釋放列表”中的下一個(gè)指針指向這個(gè)被delete的對(duì)象內(nèi)存地址。當(dāng)應(yīng)用程序再次使用這塊內(nèi)存時(shí),指針被覆寫為對(duì)象的地址。通過這種方法,就不需要預(yù)先實(shí)例化內(nèi)存空間。

    使用釋放對(duì)象的內(nèi)存來將內(nèi)存塊連接在一起意味著對(duì)象的內(nèi)存空間需要足夠容納一個(gè)指針占用內(nèi)存空間的大小。構(gòu)造函數(shù)初始化列表中的代碼保證了最小內(nèi)存塊大小不會(huì)小于指針占用內(nèi)存塊的大小。

    類的析構(gòu)函數(shù)通過釋放堆內(nèi)存池或者遍歷“釋放列表”并逐個(gè)釋放內(nèi)存塊來實(shí)現(xiàn)內(nèi)存的釋放。由于Allocator類對(duì)象常被用作是static的,那么Allocator對(duì)象的釋放是在程序結(jié)束時(shí)。對(duì)于大多數(shù)嵌入式設(shè)備,應(yīng)用只在人們拔斷電源時(shí)才會(huì)結(jié)束。因此,對(duì)于這種嵌入式設(shè)備,析構(gòu)函數(shù)的作用就顯無所謂了。

    如果使用堆內(nèi)存塊模式,除非所有分配的內(nèi)存被鏈接在“釋放列表”,應(yīng)用結(jié)束時(shí)分配的內(nèi)存塊不能被釋放。因此,所有對(duì)象應(yīng)該在程序結(jié)束時(shí)被“刪除”(指放入“釋放列表”)。這似乎是內(nèi)存泄漏,也帶來了一個(gè)有趣的問題。Allocator應(yīng)該跟蹤正在使用和已經(jīng)釋放的內(nèi)存塊嗎?答案是否定的。以為一旦一塊內(nèi)存通過指針被應(yīng)用所使用,那么應(yīng)用程序有責(zé)任在程序結(jié)束前通過調(diào)用Deallocate()返回該內(nèi)存塊指針給Allocator。這樣的話,我么只需要跟蹤釋放的內(nèi)存塊。

    代碼的使用

    Allocator易于使用,因此創(chuàng)建宏來自動(dòng)在客戶端類中實(shí)現(xiàn)接口。宏提供一個(gè)靜態(tài)類型的Allocator實(shí)例和兩個(gè)成員函數(shù):操作符new和操作符delete。通過重寫new和delete操作符,Allocator截取并處理所有的客戶端類的內(nèi)存分配行為。

    DECLARE_ALLOCATOR宏提供頭文件接口,并且應(yīng)該在類定義時(shí)將其包含在內(nèi),如下面這樣:

    #include "Allocator.h"class MyClass{

    操作符new函數(shù)調(diào)用Allocator創(chuàng)建類實(shí)例所需要的內(nèi)存空間。內(nèi)存分配后,根據(jù)定義,操作符new調(diào)用該類的構(gòu)造函數(shù)。重寫的new只修改了內(nèi)存的分配任務(wù)。構(gòu)造函數(shù)的調(diào)用由語言保證。刪除對(duì)象時(shí),系統(tǒng)首先調(diào)用析構(gòu)函數(shù),然后調(diào)用執(zhí)行操作符delete函數(shù)。操作符delete使用Deallocate()函數(shù)將內(nèi)存塊加入到“釋放列表”中。

    盡管沒有明確聲明,操作符delete是靜態(tài)函數(shù)(靜態(tài)函數(shù)才能調(diào)用靜態(tài)成員)。因此它不能被聲明為virtual。這樣看上去通過基類的指針刪除對(duì)象不能達(dá)到刪除真實(shí)對(duì)象的目的。畢竟,調(diào)用基類指針的靜態(tài)函數(shù)只會(huì)調(diào)用基類的成員函數(shù),而不是其真實(shí)類型的成員函數(shù)。然而,我們知道,調(diào)用操作符delete時(shí)首先調(diào)用析構(gòu)函數(shù)。修飾為virtual的析構(gòu)函數(shù)會(huì)實(shí)際調(diào)用子類的析構(gòu)函數(shù)。類的析構(gòu)函數(shù)執(zhí)行完后,子類的操作符delete函數(shù)被調(diào)用。因此實(shí)際上,由于虛析構(gòu)函數(shù)的調(diào)用,重寫的操作符delete會(huì)在子類中調(diào)用。所以,使用基類指針刪除對(duì)象時(shí),基類對(duì)象的析構(gòu)函數(shù)必須聲明為virtual。否則,將會(huì)不能正確調(diào)用析構(gòu)函數(shù)和操作符delete。

    IMPLEMENT_ALLOCATOR宏是接口的源文件實(shí)現(xiàn)部分,并應(yīng)該放置于源文件中。

    IMPLEMENT_ALLOCATOR(MyClass, 0, 0)

    使用上述宏后,可以如下面一樣創(chuàng)建并銷毀類的實(shí)例,同事循環(huán)使用釋放的內(nèi)存空間。

    MyClass* myClass=new MyClass();delete myClass;

    Allocator類支持單繼承和多繼承。例如,Derived類繼承Base類,如下代碼是正確的。

    Base* base=new Derived;

    運(yùn)行時(shí)

    運(yùn)行時(shí),Allocator初始化時(shí)“釋放列表”中沒有可重用的內(nèi)存塊。因此,第一次調(diào)用Allocate()將從內(nèi)存池或者堆中獲取內(nèi)存空間。隨著程序的執(zhí)行,系統(tǒng)不斷使用對(duì)象會(huì)造成分配器的波動(dòng)。并且只有當(dāng)釋放列表無法提供內(nèi)存時(shí),新內(nèi)存才會(huì)被申請(qǐng)和創(chuàng)建。最終,系統(tǒng)使用對(duì)象的實(shí)例會(huì)固定,因此每次內(nèi)存分配將會(huì)使用已經(jīng)存在的內(nèi)存空間二不是再從內(nèi)存池或者堆中申請(qǐng)。

    與使用內(nèi)存管理器分配所有對(duì)象內(nèi)存相比,Allocator分配器更加高效。內(nèi)存分配時(shí),內(nèi)存指針僅僅是從“釋放列表”中彈出,速度非???。內(nèi)存釋放時(shí)也僅僅是將內(nèi)存指針放入到“釋放列表”當(dāng)中,速度也十分快。

    基準(zhǔn)測(cè)試

    在Windows PC上使用Allocator和全局堆內(nèi)存的對(duì)比性能測(cè)試顯示出Allocator的高性能。測(cè)試分配和釋放20000個(gè)4096和2048大小的內(nèi)存塊來測(cè)試分配和釋放內(nèi)存的速度。測(cè)試的算法詳見附件中的代碼。

    AllocatorModeRunBenchmark Time (mS)
    Global HeapDebug Heap11640
    Global HeapDebug Heap21864
    Global HeapDebug Heap31855
    Global HeapRelease Heap155
    Global HeapRelease Heap247
    Global HeapRelease Heap347
    AllocatorStatic Pool119
    AllocatorStatic Pool27
    AllocatorStatic Pool37
    AllocatorHeap Blocks130
    AllocatorHeap Blocks27
    AllocatorHeap Blocks37

    使用調(diào)試模式執(zhí)行時(shí),Windows使用調(diào)試堆內(nèi)存。調(diào)試堆內(nèi)存添加額外的安全檢查降低了性能。發(fā)布堆內(nèi)存性能更好,因?yàn)椴皇褂冒踩珯z查。通過在Visual Studio工程選項(xiàng)中,設(shè)置【調(diào)試】-【環(huán)境】中_NO_DEBUG_HEAP=1來禁止調(diào)試內(nèi)存模式。

    全局調(diào)試堆內(nèi)存模式需要平均1.8秒,是最慢的。釋放對(duì)內(nèi)存模式50毫秒左右,稍快。基準(zhǔn)測(cè)試的場(chǎng)景非常簡(jiǎn)單,實(shí)際情況下,不同大小的內(nèi)存塊和隨機(jī)的申請(qǐng)、釋放可能產(chǎn)生不同的結(jié)果。然而,最簡(jiǎn)單的也最能說明問題。內(nèi)存管理器比Allocator內(nèi)存分配器慢,并且很大程度上依賴于平臺(tái)的實(shí)現(xiàn)能力。

    內(nèi)存分配器Allocator使用靜態(tài)內(nèi)存模式不依賴于堆內(nèi)存的分配。一旦“釋放列表”中含有內(nèi)存塊后,其執(zhí)行時(shí)間大約為7毫秒。第一次耗時(shí)19毫秒用于將內(nèi)存池中的內(nèi)存防止到Allocator分配器中管理。

    Aloocator使用堆內(nèi)存模式時(shí),當(dāng)“釋放列表”中有可重用的內(nèi)存后,其速度與靜態(tài)內(nèi)存模式一樣快。堆內(nèi)存模式依賴于全局堆來獲取內(nèi)存塊,但是循環(huán)利用“釋放列表”中的內(nèi)存。第一次需要申請(qǐng)堆內(nèi)存,耗時(shí)30毫秒。由于重用“釋放列表”中的內(nèi)存,之后的申請(qǐng)僅需要7毫秒。

    上面的基準(zhǔn)測(cè)試結(jié)果表示,Allocator內(nèi)存分配器更加高效,擁有7倍于Windows全局發(fā)布堆內(nèi)存模式的速度。

    對(duì)于嵌入式系統(tǒng),我使用Keil在ARM STM32F4 CPU(168Hz)上運(yùn)行相同測(cè)試。由于資源限制,我將最大內(nèi)存塊數(shù)量降低到500,單個(gè)內(nèi)存塊大小降低到32和16字節(jié)。下面是結(jié)果:

    AllocatorModeRunBenchmark Time (mS)
    Global HeapRelease111.6
    Global HeapRelease211.6
    Global HeapRelease311.6
    AllocatorStatic Pool10.85
    AllocatorStatic Pool20.79
    AllocatorStatic Pool30.79
    AllocatorHeap Blocks11.19
    AllocatorHeap Blocks20.79
    AllocatorHeap Blocks30.79

    基于ARM的基準(zhǔn)測(cè)試顯示,使用Allocator分配器的類性能快15倍。這個(gè)結(jié)果會(huì)讓Keil堆內(nèi)存的表現(xiàn)相形見絀?;鶞?zhǔn)測(cè)試分配500個(gè)16字節(jié)大小的內(nèi)存塊進(jìn)行測(cè)試。每個(gè)16字節(jié)大小的內(nèi)存刪除后申請(qǐng)500個(gè)32字節(jié)大小的內(nèi)存塊。全局堆內(nèi)存耗時(shí)11.6毫秒,而且,在內(nèi)存碎片化后,內(nèi)存管理器可能會(huì)在沒有安全檢查的情況下耗時(shí)更大。

    分配器決議

    第一個(gè)決定是你是否需要使用分配器。如果你的項(xiàng)目不關(guān)心執(zhí)行的速度和是否需要容錯(cuò),那么你可能不需要自定義的分配器,全局堆分配管理器足夠用了。

    另一方面,如果你需要考慮執(zhí)行速度和容錯(cuò)管理,分配器會(huì)起到作用。你需要根據(jù)項(xiàng)目的需要選擇分配器的模式。重要任務(wù)系統(tǒng)的設(shè)計(jì)可能強(qiáng)制要求使用全局堆內(nèi)存。而動(dòng)態(tài)分配內(nèi)存可能更高效,設(shè)計(jì)更優(yōu)雅。這種情況下,你可以在調(diào)試開發(fā)時(shí)使用堆內(nèi)存模式獲取內(nèi)存使用參數(shù),然后發(fā)布時(shí)切換到靜態(tài)內(nèi)存池模式避免內(nèi)存分配帶來的性能消耗。一些編譯時(shí)的宏可用于模式的切換。

    另外,堆內(nèi)存模式可能對(duì)應(yīng)用更適合。該模式利用堆來獲取新內(nèi)存,同時(shí)阻止了堆碎片錯(cuò)誤。當(dāng)“釋放列表”鏈接足夠的內(nèi)存塊后更能加快內(nèi)存的分配效率。

    在源代碼中沒有實(shí)現(xiàn)的涉及多線程的問題不在本文的討論范圍內(nèi)。運(yùn)行系統(tǒng)一會(huì)后,可以方便地使用GetlockCount函數(shù)和GetName函數(shù)獲取內(nèi)存塊數(shù)量和名稱。這些度量參數(shù)提供關(guān)于內(nèi)存分配的信息。盡量多申請(qǐng)點(diǎn)內(nèi)存,以便給分配盤一些彈性來避免內(nèi)存耗盡。

    調(diào)試內(nèi)存泄漏

    調(diào)試內(nèi)存泄漏非常困難,原因是堆內(nèi)存就像一個(gè)黑盒,對(duì)于分配對(duì)象的類型和大小是不可見的。使用Allocator,由于Allocator跟蹤記錄內(nèi)存塊的總數(shù),內(nèi)存泄漏檢查變得簡(jiǎn)單一點(diǎn)。對(duì)每個(gè)分配器實(shí)例重復(fù)輸出(例如輸出到終端)GetBlockCount和GetName并比對(duì)它們的不同能讓我們更好的了解分配器對(duì)內(nèi)存的分配。

    錯(cuò)誤處理

    C++中使用new_handler函數(shù)處理內(nèi)存分配錯(cuò)誤。如果內(nèi)存管理器在申請(qǐng)內(nèi)存時(shí)發(fā)生錯(cuò)誤,用戶的錯(cuò)誤處理函數(shù)就會(huì)被調(diào)用。通過將用戶的錯(cuò)誤處理函數(shù)地址復(fù)制給new_handler,內(nèi)存管理器就能調(diào)用用戶自定義的錯(cuò)誤處理程序。為了讓Allocator類的錯(cuò)誤處理機(jī)制與內(nèi)存管理器保持一致,分配器也通過new_handler調(diào)用錯(cuò)誤處理函數(shù),集中處理所有的內(nèi)存分配錯(cuò)誤。

    static void out_of_memory(){ // new-handler function called by Allocator when pool is out of memory

    限制

    分配器類不支持?jǐn)?shù)組對(duì)象的內(nèi)存分配。為每一個(gè)對(duì)象創(chuàng)建分開的內(nèi)存是無法保證的,因?yàn)閚ew的多次調(diào)用不保證內(nèi)存塊的連續(xù),但這又是數(shù)組所需要的。因此Allocator只支持固定大小內(nèi)存塊的分配,對(duì)象數(shù)組不支持。

    移植問題

    Allocator在靜態(tài)內(nèi)存池耗盡時(shí)調(diào)用new_handle指向的函數(shù),這對(duì)于某些系統(tǒng)不合適。假設(shè)new_handle函數(shù)沒返回,例如無盡的循環(huán)或者斷言,調(diào)用這個(gè)函數(shù)不起任何作用。使用固定內(nèi)存池時(shí)這無濟(jì)于事。

    進(jìn)一步閱讀

    請(qǐng)閱讀相關(guān)文章:使用快速固定大小分配器替換malloc/free來查看如何使用Allocator更為快速的替換C++運(yùn)行工具中的malloc和free函數(shù)。

    下載源碼:Download Allocator.zip – 5.4 KB

    譯文鏈接:http://www.codeceo.com/article/efficient-cpp-memory-allocator.html

    英文原文:An Efficient C++ Fixed Block Memory Allocator

    翻譯作者:碼農(nóng)網(wǎng) – 蘇文鵬

網(wǎng)站首頁   |    關(guān)于我們   |    公司新聞   |    產(chǎn)品方案   |    用戶案例   |    售后服務(wù)   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區(qū)    電話:010-     郵箱:@126.com

備案號(hào):冀ICP備2024067069號(hào)-3 北京科技有限公司版權(quán)所有