• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            關(guān)于系統(tǒng)緩存的問題-物理內(nèi)存消耗遠(yuǎn)遠(yuǎn)多于實(shí)際占用物理內(nèi)存

            【 某某提到: 】
            : 一臺服務(wù)器裝有windows server 2008 r2,安裝16G內(nèi)存并設(shè)置16G虛擬內(nèi)存。最近在運(yùn)行一個(gè)用C#編寫的大規(guī)模計(jì)算程序時(shí)發(fā)現(xiàn),有很大一部分物理內(nèi)存被莫名其妙地消耗了。資源監(jiān)視器顯示該程序占用物理內(nèi)存不到5G,但是總的物理內(nèi)存消耗接近10G,可用物理內(nèi)存僅剩6G。隨著運(yùn)?
            : 除了這個(gè)程序之外沒有其它程序大量占用內(nèi)存。這個(gè)程序有大量磁盤IO操作,在運(yùn)行中會不時(shí)地調(diào)用GC.Collect()以及時(shí)清理不用的內(nèi)存。這個(gè)實(shí)驗(yàn)中用到的一系列程序的結(jié)構(gòu)基本相同,都會不時(shí)調(diào)用GC清理,但其它程序的內(nèi)存使用都正常,只有這個(gè)程序會出現(xiàn)占用內(nèi)存是實(shí)際使用的
            : 請問為什么會出現(xiàn)這樣莫名其妙多占用內(nèi)存的情況呢?謝謝大家


            這個(gè)既不是應(yīng)用本身的bug,也不是系統(tǒng)的memory leak。

            當(dāng)前資源監(jiān)視器中關(guān)于系統(tǒng)物理內(nèi)存,有這么幾個(gè)統(tǒng)計(jì)項(xiàng),可用、緩存、總數(shù)、已安裝;其中"緩存"這項(xiàng),代表著已用于文件系統(tǒng)、網(wǎng)絡(luò)等等子系統(tǒng)的數(shù)據(jù)緩沖存儲的內(nèi)存容量,其中包含數(shù)量巨大的駐留在物理內(nèi)存中的數(shù)據(jù)頁面。而這樣的物理內(nèi)存消耗并沒有歸入任何一個(gè)進(jìn)程列表顯示的進(jìn)程所占用的物理內(nèi)存。這就是為什么下面公式,

            進(jìn)程列表顯示的所有進(jìn)程所占用的物理內(nèi)存之和 + 可用物理內(nèi)存 < 物理內(nèi)存總數(shù)

            ,成立的原因所在。

            導(dǎo)致這一現(xiàn)象的原因,從這個(gè)大規(guī)模計(jì)算程序的行為描述看,基本可以斷定是由于以下兩點(diǎn),
            1)應(yīng)用本身的大規(guī)模數(shù)據(jù)駐留物理內(nèi)存,導(dǎo)致parser.exe進(jìn)程龐大的working set;
            2)大量頻繁的IO操作,引起大量的物理內(nèi)存為系統(tǒng)緩存所占用;

            對于1),必須注意,GC.Collect()只是設(shè)置使能垃圾收集的標(biāo)志位,并沒有立即啟動垃圾收集過程,這個(gè)過程的實(shí)際啟動時(shí)刻由CLR來動態(tài)決議;

            所以如果要獲得即時(shí)的托管內(nèi)存的釋放,并進(jìn)一步釋放物理內(nèi)存以減小當(dāng)前進(jìn)程的working set,可以使用AppDomain這個(gè).net下可以用來資源劃分、獲取和釋放的,在概念上近似于輕量級進(jìn)程的編程語義;在AppDomain中獲取的各種資源,包括托管內(nèi)存、加載其中的各個(gè)assembly以及CCW等,在此AppDomain被釋放時(shí)都被相應(yīng)的及時(shí)釋放(或者引用計(jì)數(shù)遞減)。

            對于2),重新觀察先前的設(shè)計(jì)實(shí)現(xiàn)和模型,考慮是否能把一些分散的IO操作合并起來進(jìn)行,比如,
            for(long i=0; i < Count; ++i)
            {
              ...
              objIO.Operation(Data[i], 1);
              ...
            }
            修改為
            for(long i=0; i < Count; ++i)
            {
              ...
              ...
            }
            objIO.Operation(Data, Count);
            這樣對于提高應(yīng)用的IO效率以及提升系統(tǒng)緩存利用率應(yīng)當(dāng)會有幫助。


            對于2),系統(tǒng)緩存隨著這個(gè)大規(guī)模計(jì)算應(yīng)用的進(jìn)行而逐步增大,并最后導(dǎo)致整個(gè)系統(tǒng)無法獲取的物理內(nèi)存而無法繼續(xù)運(yùn)行的現(xiàn)象,估計(jì)即使采用了在上文提出的,在應(yīng)用程序代碼中盡可能合并IO操作,減少IO次數(shù)的方法,也不會改善系統(tǒng)緩存占用物理內(nèi)存數(shù)量過大的問題。這個(gè)問題本質(zhì)上是Windows操作系統(tǒng)本身從NT時(shí)代到現(xiàn)在,一直存在的問題,主要是圍繞著Windows kernel中的Cache mananger以及memory manager核心態(tài)組件的實(shí)現(xiàn)機(jī)制而產(chǎn)生的。

            根據(jù)目前的Cc(對Cache manager的簡稱,在WindowsResourceKernel開源項(xiàng)目中,Cache manager相關(guān)模塊的函數(shù)都以Cc作為前綴,比如CcCopyRead,CcFlushCache等,Memory manager也同樣簡稱Mm)的實(shí)現(xiàn)機(jī)制,所有對文件系統(tǒng)的訪問,包括本地和網(wǎng)絡(luò),都會首先由Cc對相關(guān)頁面作緩存映射,隨著頻繁的IO的操作,被Cc緩存的頁面也迅速遞增,而被緩存頁面占用多少物理內(nèi)存,這是由Windows kernel中的Memory manager決定。目前在64位平臺上,系統(tǒng)緩存最高可達(dá)1TB,所以這個(gè)應(yīng)用進(jìn)程的運(yùn)行中出現(xiàn)分配8G的緩存是完全可能的,但同時(shí)問題也隨之而來,那就是系統(tǒng)緩存占用了過多的物理內(nèi)存,導(dǎo)致其他進(jìn)程以及內(nèi)核本身無法申請足夠的物理內(nèi)存,最后致使系統(tǒng)“僵死”;

            對于這個(gè)問題,微軟提供了“Microsoft Windows Dynamic Cache Service”工具來提供對系統(tǒng)緩存的工作集working set容量(也就是駐留物理內(nèi)存的大小)的控制,這個(gè)工具主要是對SetSystemFileCacheSize的封裝,可以設(shè)置系統(tǒng)緩存容量的上下限。

            但這只是一種臨時(shí)的解決方案,因?yàn)閼?yīng)用雖然可以通過上面這個(gè)Dynamic Cache Service來設(shè)置和限制系統(tǒng)緩存容量的大小,但是如何確定緩存容量大小的非常困難,如果過小,所有IO性能大受影響,整個(gè)Cc如同虛設(shè);如果過大(等價(jià)于不受限),那么系統(tǒng)緩存占用過多物理內(nèi)存導(dǎo)致系統(tǒng)僵死的現(xiàn)象就會重現(xiàn)。

            所以從根本上看,這個(gè)問題應(yīng)由包括Cc和Mm在內(nèi)的整個(gè)Windows kernel作出完整一致的調(diào)整,但從目前的實(shí)現(xiàn)看要完成整個(gè)方案改動很大,據(jù)稱這個(gè)改進(jìn)可能會考慮包含在Win7中發(fā)布。

            Microsoft Windows Dynamic Cache Service下載,
            http://www.microsoft.com/downloads/en/details.aspx?FamilyID=e24ade0a-5efe-43c8-b9c3-5d0ecb2f39af&displaylang=en

            Microsoft Windows Dynamic Cache Service相關(guān)的介紹,
            http://blogs.msdn.com/b/ntdebugging/archive/2009/02/06/microsoft-windows-dynamic-cache-service.aspx

            posted @ 2010-12-11 11:19 flagman 閱讀(6211) | 評論 (1)編輯 收藏

            一個(gè)抽號碼問題

            前些天在論壇上看到一個(gè)看似簡單,其實(shí)挺有意思的問題:

            【20個(gè)連續(xù)的號碼中抽出6個(gè)來,要求6個(gè)號碼不能相連,有多少種抽法?】

            這問題的本意應(yīng)該是兩兩不相連的情況。

            首先定義一個(gè)函數(shù),F(xiàn)(m,p), m是確定抽出幾個(gè)號碼,p是總共有幾個(gè)號碼,那么
            F(m,p)的值域就是代表在p個(gè)連續(xù)號碼中,抽出兩兩不相連的m個(gè)號碼,總共有幾種組合;

            接著確定狀態(tài)轉(zhuǎn)移方程,經(jīng)過觀察,p必須滿足條件p >= m*2-1,否則F就為0,同時(shí)
            F(6,20) = F(5,18) + F(5,17) + F(5,16) + ... + F(5,9);

            因此可以得出如下狀態(tài)轉(zhuǎn)移方程,
            當(dāng) p > m*2-1,F(xiàn)(m,p) = Sigma(F(m-1,q)) + 1;其中q 從(m-1)*2 到 p-2;
            當(dāng) p == m*2-1,F(xiàn)(m,p) = 1;
            當(dāng) p < m*2-1,F(xiàn)(m,p) = 0;

            雖然分析到此,已可以著手具體實(shí)現(xiàn),但是還是有些問題值得進(jìn)一步分析,比如F(m,p)和F(m,p-1)之間存在何種關(guān)系,若使用遞歸,就當(dāng)前這個(gè)問題效率估計(jì)會是問題;

            因此對此方程進(jìn)一步分析,
            F(5,18) = Sigma(F(4,q))+ F(4,7);q從8到16
            F(5,17) = Sigma(F(4,q))+ F(4,7);q從8到8;
            ...
            可進(jìn)一步推出,
            當(dāng) p > m*2-1, F(m,p) = F(m,p-1) + F(m-1,p-2);

            這樣我們就得到了可以進(jìn)行遞推實(shí)現(xiàn)的轉(zhuǎn)態(tài)轉(zhuǎn)移方程;
            另外,對于m == 1的情形,顯然F(1,p) = p ;


            #include<stdio.h>
            #include<conio.h>

            #define MAXLEN 10000

            static int F[MAXLEN];
            static int R[MAXLEN];

            int Compute(
                const int cM,
                const int cP)
            {
              if (cM <= 0 || cP < (cM*2-1))
                return 0;
              if (cM == 1)
                return cP;
              if (cP == cM*2-1)
                return 1;

              for(int i = 0; i < MAXLEN; ++i) R[i] = i;

              for(int m = 2; m <= cM; ++m)
              {
                int floof = 2*m;
                int ceiling = cP-2*(cM-m);
                F[2*m-1] = 1;
                for(int p = floof; p <= ceiling; ++p)
                    F[p] = F[p-1] + R[p-2];
                for(int j = floof; j <= ceiling; ++j)
                    R[j] = F[j];
              }
              return F[cP];
            }

            main()
            {
              Compute(6,20);
            //  Compute(6,19);
            //  Compute(5,18);
            //  Compute(5,17);
            //  Compute(4,16);
            //  Compute(6,13);
            //  Compute(6,12);

            //  Compute(5,11);
            //  Compute(5,10);
            //  Compute(4,9);
            //  Compute(4,8);
            //  Compute(3,7);
              return 0;
            }

            接著再對目前的整個(gè)實(shí)現(xiàn)做下復(fù)雜度分析,主要處理部分基本上由兩個(gè)循環(huán)構(gòu)成,對于R數(shù)組的初始化可作為常數(shù)項(xiàng)不計(jì),那么

            大O( F(m,p) ) = O( m*(ceiling-floor) )
                          = O( m*(p-2*m) )
                          近似于O( m*p ),
            若m << p,顯然O(F(m,p)) = p;
            若m 近似 p, 但事實(shí)上必須p >= 2*m - 1,否則F值就接近0或1,因此O(F(m,p)) 近似于const;
            所以綜合來看上面的這個(gè)實(shí)現(xiàn)在時(shí)間上是個(gè)線性復(fù)雜度的實(shí)現(xiàn);在空間上,使用了兩個(gè)長度至少為p的數(shù)組,個(gè)人認(rèn)為可以對此進(jìn)行進(jìn)一步優(yōu)化。

            對于F(6,20) = 5005

            整個(gè)實(shí)現(xiàn)在TC++ 3.0上驗(yàn)證通過。


            posted @ 2010-12-03 10:53 flagman 閱讀(1331) | 評論 (1)編輯 收藏

            思考系統(tǒng)API設(shè)計(jì)的問題

            最近正好在思考系統(tǒng)API設(shè)計(jì)中考量的一些問題,

            【某網(wǎng)友討論到】
            : 那地址是不是同一個(gè)地址呢。我現(xiàn)在的理解是這樣的,假設(shè)有巨大的真實(shí)內(nèi)存。windows首先將高2G的內(nèi)存自己占了,用作各種內(nèi)核對象。這2G內(nèi)存共享給每個(gè)進(jìn)程,但進(jìn)程不能直接訪問,只能通過windows給定的函數(shù)訪問。
            : 然后每個(gè)進(jìn)程都給他2G內(nèi)存,進(jìn)程如果創(chuàng)建自己的對象就放到自己那2G內(nèi)存里面,如果要建立內(nèi)核對象就放到共享的那高2G里面去。
            : 所以不同進(jìn)程如果可以訪問高2G內(nèi)存的話,任何進(jìn)程訪問到同一個(gè)高地址實(shí)際上都是訪問到同一個(gè)對象。但如果訪問低2G地址的話,不同進(jìn)程是對應(yīng)不同的對象的。



            在不同的進(jìn)程中,詢問同一個(gè)內(nèi)核對象的實(shí)際地址(無論是線性地址還是物理地址),是無意義的:

            首先,內(nèi)核對象只能由在內(nèi)核態(tài)下的例程才能直接訪問,在我們?nèi)粘5拇a中,所調(diào)用的Windows API,比如CreateFile, (注意調(diào)用剛開始時(shí)是處于用戶態(tài)下的),一般都會在ntdll.dll中找到對應(yīng)的內(nèi)核函數(shù)或例程,接著系統(tǒng)切換到內(nèi)核態(tài),開始調(diào)用實(shí)際對應(yīng)的內(nèi)核函數(shù)(KiCreateFile),這個(gè)時(shí)候才會去訪問內(nèi)核對象的實(shí)際地址,然后建立一個(gè)該內(nèi)核對象對應(yīng)當(dāng)前進(jìn)程的Handle,并把它返回給caller,同時(shí)切換回用戶態(tài);因此,對于用戶態(tài)程序來說,只要且只能知道該內(nèi)核對象在當(dāng)前進(jìn)程中的對應(yīng)的Handle就可以對其進(jìn)行操作了;

            其次,這樣的設(shè)計(jì)是出于對OS核心數(shù)據(jù)結(jié)構(gòu)(當(dāng)然包括我們正在討論的內(nèi)核對象)的保護(hù);如果用戶態(tài)程序可以輕易的獲取內(nèi)核數(shù)據(jù)結(jié)構(gòu)的實(shí)際地址,那么對于整個(gè)OS的安全和穩(wěn)定顯然構(gòu)成很大的問題;一個(gè)用戶態(tài)的誤操作可以輕易的引起整個(gè)OS的崩潰,而有了這一層的保護(hù),崩潰的只是當(dāng)前進(jìn)程而不是整個(gè)系統(tǒng);

            接著上面這點(diǎn),也可以看出,內(nèi)核對象的如此設(shè)計(jì)達(dá)到了接納OS本身的平滑演進(jìn)的目的。從Windows 3.0到95/98,從NT到Win2k/XP,再到眼下的Vista/Win7,Windows操作系統(tǒng)本身發(fā)生了巨大的變化和進(jìn)步,采納了無數(shù)的新技術(shù)新方法,但是它基本的系統(tǒng)應(yīng)用編程接口,也就是我們所熟知的windows API,卻并沒有發(fā)生太大的改變,很多Win 3.0 這個(gè)16位OS時(shí)代的程序代碼只要當(dāng)初設(shè)計(jì)規(guī)范編碼規(guī)范,稍許修改就可以在最新版的OS上運(yùn)行如飛;是什么做到了這些?也就是所謂的極為重要的向后兼容性,我個(gè)人認(rèn)為,把操作系統(tǒng)的重要/主要功能抽象成內(nèi)核對象,并通過一套極為solid的API暴露出來,達(dá)成了這個(gè)目標(biāo)。

            這是一種更高層次上的面向?qū)ο螅褜?shí)現(xiàn)的細(xì)節(jié),把系統(tǒng)的復(fù)雜,簡單而優(yōu)雅的封裝了起來。你只要調(diào)用CreateFile去建個(gè)文件或管道或郵槽,不用擔(dān)心當(dāng)前OS是Windows 3.0還是Win7,獲得的Handle,你也不用去關(guān)心它以及它所指向的內(nèi)核對象是Windows 3.0的實(shí)現(xiàn)還是Win7的實(shí)現(xiàn)。

            Windows上所有的精彩幾乎都是基于這套通過內(nèi)核對象概念抽象并暴露的API基礎(chǔ)之上,COM/OLE,這個(gè)二十年前震撼性的ABI和IPC范疇的技術(shù)規(guī)范,其中很多的設(shè)計(jì)思路也是植根于內(nèi)核對象的設(shè)計(jì)理念,如COM對象的引用計(jì)數(shù)和內(nèi)核對象引用計(jì)數(shù),IUnknown和Windows Handle(前者是指向某個(gè)二進(jìn)制兼容的組件對象,后者引用或間接指向某個(gè)內(nèi)核對象,都是對于某個(gè)復(fù)雜概念的一致性抽象表述),等等;

            十年前的.net,本來是作為COM的升級版本推出,把COM/OLE的實(shí)現(xiàn)復(fù)雜性封裝在了虛擬機(jī)平臺CLR里面,而從這個(gè)虛擬機(jī)的開源實(shí)現(xiàn)SSCLI,我們可以看到大量的COM機(jī)制在.net的具體實(shí)現(xiàn)里面起了舉足輕重的作用。在這些VM中大量symbol有著COR的前綴或者后綴,COR指代什么?Common Object Runtime, 原來CLR/SSCLI的設(shè)計(jì)思路也是把OS通過虛擬機(jī)VM的形式,并通過common object向應(yīng)用程序暴露功能。

            小結(jié)一下,
            OS內(nèi)核對象API,三十年前系統(tǒng)級別的對象抽象;
            COM/OLE,二十年前二進(jìn)制組件級別的對象抽象;
            .net/CLR, 十年前虛擬機(jī)平臺級別的對象抽象;

            寫到這里倒是引起了我其他的一些思考,軟件工業(yè)界一直以來對面向?qū)ο驩O是熱火朝天,特別是語言層面,從C++/Java/C#到Python/JScript,不一而足;

            但是我們有沒有從根本性的設(shè)計(jì)理念上對面向?qū)ο螅旒{雅言了呢?

            如果現(xiàn)在設(shè)計(jì)Windows這套API的任務(wù)放在大家面前,會采用內(nèi)核對象/Handle方案還是直接指向OS內(nèi)部數(shù)據(jù)結(jié)構(gòu)的方式來暴露功能?

            從三十年前的這套API的設(shè)計(jì)中,我們真的可以學(xué)到很多。


             

            posted @ 2010-12-01 21:28 flagman 閱讀(10191) | 評論 (0)編輯 收藏

            僅列出標(biāo)題
            共2頁: 1 2 
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            国产综合精品久久亚洲| 久久综合噜噜激激的五月天| 久久国产精品成人免费| 99久久99久久精品国产片果冻| 久久99久久成人免费播放| 蜜桃麻豆www久久国产精品| 亚洲人成伊人成综合网久久久| 蜜臀av性久久久久蜜臀aⅴ | 亚洲精品tv久久久久久久久| 久久婷婷五月综合97色| 性高湖久久久久久久久AAAAA| 精品熟女少妇av免费久久| 久久天天躁狠狠躁夜夜不卡| 亚洲国产精品一区二区久久hs| 久久精品中文字幕有码| 99久久综合狠狠综合久久止| 久久综合亚洲色一区二区三区 | 99久久免费只有精品国产| 久久精品一本到99热免费| 久久精品国产福利国产秒| 亚洲欧美另类日本久久国产真实乱对白 | 久久亚洲中文字幕精品一区四| 无码人妻久久久一区二区三区| 久久国产高清一区二区三区| 97精品久久天干天天天按摩| 久久精品国产亚洲αv忘忧草 | 国产成人久久精品二区三区| 久久人人爽人人爽人人片AV麻烦 | 熟妇人妻久久中文字幕| 久久天天躁狠狠躁夜夜不卡| 亚洲精品tv久久久久| 久久精品亚洲男人的天堂| 国产福利电影一区二区三区,免费久久久久久久精 | 欧美牲交A欧牲交aⅴ久久| 一本一本久久a久久精品综合麻豆| 婷婷久久综合九色综合98| 99久久99久久精品免费看蜜桃| 无遮挡粉嫩小泬久久久久久久 | 四虎影视久久久免费观看| 久久av高潮av无码av喷吹| 久久97久久97精品免视看秋霞|