電腦運(yùn)行內(nèi)存12g和4 g
現(xiàn)在手機(jī)運(yùn)行內(nèi)存已經(jīng)非常夸張了,16G的運(yùn)行內(nèi)存已經(jīng)出來(lái)了,而且各家的旗艦手機(jī)的頂配版本都標(biāo)配16+512G超大內(nèi)存組合了 。但是普通人買(mǎi)手機(jī)還在考慮8G和12G的運(yùn)行內(nèi)存,我們也想嘗試一下16G運(yùn)行...
2025.07.03COPYRIGHT ? 2023
粵ICP備2021108052號(hào)
郵箱:611661226@qq.com
留言給我響應(yīng)時(shí)間:指的就是,我們執(zhí)行一個(gè)程序,到底需要花多少時(shí)間。花的時(shí)間越少,自然性能就越好。吞吐率:在一定的時(shí)間范圍內(nèi),到底能處理多少事情。這里的“事情”,在計(jì)算機(jī)里就是處理的數(shù)據(jù)或者執(zhí)行的程序指令。
我們一般把性能,定義成響應(yīng)時(shí)間的倒數(shù),也就是: 性能 = 1/響應(yīng)時(shí)間
程序運(yùn)行的時(shí)間=程序運(yùn)行結(jié)束的時(shí)間-程序開(kāi)始運(yùn)行的時(shí)間
但是,計(jì)算機(jī)可能同時(shí)運(yùn)行著好多個(gè)程序,CPU實(shí)際上不停地在各個(gè)程序之間進(jìn)行切換。在這些走掉的時(shí)間里面,很可能CPU切換去運(yùn)行別的程序了。所以這個(gè)時(shí)間并不準(zhǔn)。
我們使用time命令統(tǒng)計(jì)運(yùn)行時(shí)間:
$ time seq 1000000 | wc -l1000000real0m0.101suser0m0.031ssys0m0.016s
其中real就是Wall Clock Time,而程序?qū)嶋H花費(fèi)的CPU執(zhí)行時(shí)間,就是user time加上sys time。
我們下面對(duì)程序的CPU執(zhí)行時(shí)間進(jìn)行拆解:
程序的CPU執(zhí)行時(shí)間=CPU時(shí)鐘周期數(shù)×?xí)r鐘周期時(shí)間
時(shí)鐘周期時(shí)間:如果一臺(tái)電腦的主頻是2.8GHz,那么可以簡(jiǎn)單認(rèn)為,CPU在1秒時(shí)間內(nèi),可以執(zhí)行的簡(jiǎn)單指令的數(shù)量是2.8G條。在這個(gè)2.8GHz的CPU上,這個(gè)時(shí)鐘周期時(shí)間,就是1/2.8G。
對(duì)于上面的公式:CPU時(shí)鐘周期數(shù)還可以拆解成指令數(shù)×每條指令的平均時(shí)鐘周期數(shù)Cycles Per Instruction,簡(jiǎn)稱(chēng)CPI)。
程序的CPU執(zhí)行時(shí)間=指令數(shù)×CPI×Clock Cycle Time
由于通過(guò)提升CPU頻率已經(jīng)達(dá)到瓶頸,所以開(kāi)始推出多核CPU,通過(guò)提升“吞吐率”而不是“響應(yīng)時(shí)間”,來(lái)達(dá)到目的。
但是,并不是所有問(wèn)題,都可以通過(guò)并行提高性能來(lái)解決。如果想要使用這種思想,需要滿(mǎn)足這樣幾個(gè)條件。
所以并行計(jì)算涉及到了一個(gè)阿姆達(dá)爾定律(Amdahl’s Law)。
對(duì)于一個(gè)程序進(jìn)行優(yōu)化之后,處理器并行運(yùn)算之后效率提升的情況。具體可以用這樣一個(gè)公式來(lái)表示:
優(yōu)化后的執(zhí)行時(shí)間 = 受優(yōu)化影響的執(zhí)行時(shí)間/加速倍數(shù)+不受影響的執(zhí)行時(shí)間
比如做一段數(shù)據(jù)的計(jì)算, 本來(lái)如果整個(gè)計(jì)算單核完成需要120ns,但是我們可以將這個(gè)任務(wù)拆分成4個(gè),最后再匯總加起來(lái)。如果每個(gè)任務(wù)單獨(dú)計(jì)算需要25ns,加起來(lái)匯總需要20ns,那么4個(gè)任務(wù)并行計(jì)算需要100/4+20=25ns。
即使我們?cè)黾痈嗟牟⑿卸葋?lái)提供加速倍數(shù),比如有100個(gè)CPU,整個(gè)時(shí)間也需要100/100+20=21ns。
如下C語(yǔ)言程序例子:
// test.cint main(){int a = 1; int b = 2;a = a + b;}
我們給兩個(gè)變量 a、b分別賦值1、2,然后再將a、b兩個(gè)變量中的值加在一起,重新賦值給了a整個(gè)變量。
要讓這段程序在一個(gè)Linux操作系統(tǒng)上跑起來(lái),我們需要把整個(gè)程序翻譯成一個(gè)匯編語(yǔ)言(ASM,Assembly Language)的程序,這個(gè)過(guò)程我們一般叫編譯(Compile)成匯編代碼。
針對(duì)匯編代碼,我們可以再用匯編器(Assembler)翻譯成機(jī)器碼(Machine Code)。這些機(jī)器碼由“0”和“1”組成的機(jī)器語(yǔ)言表示。這一條條機(jī)器碼,就是一條條的計(jì)算機(jī)指令。這樣一串串的16進(jìn)制數(shù)字,就是我們CPU能夠真正認(rèn)識(shí)的計(jì)算機(jī)指令。
匯編代碼其實(shí)就是“給程序員看的機(jī)器碼”,也正因?yàn)檫@樣,機(jī)器碼和匯編代碼是一一對(duì)應(yīng)的。我們?nèi)祟?lèi)很容易記住add、mov這些用英文表示的指令,而8b 45 f8這樣的指令,由于很難一下子看明白是在干什么,所以會(huì)非常難以記憶。所以我們需要匯編代碼。
一個(gè)CPU里面會(huì)有很多種不同功能的寄存器。我這里給你介紹三種比較特殊的。
一個(gè)是PC寄存器(Program Counter Register),也叫指令地址寄存器(Instruction Address Register)。它就是用來(lái)存放下一條需要執(zhí)行的計(jì)算機(jī)指令的內(nèi)存地址。
第二個(gè)是指令寄存器(Instruction Register),用來(lái)存放當(dāng)前正在執(zhí)行的指令。
第三個(gè)是條件碼寄存器(Status Register),用里面的一個(gè)一個(gè)標(biāo)記位(Flag),存放CPU進(jìn)行算術(shù)或者邏輯計(jì)算的結(jié)果。
實(shí)際上,一個(gè)程序執(zhí)行的時(shí)候,CPU會(huì)根據(jù)PC寄存器里的地址,從內(nèi)存里面把需要執(zhí)行的指令讀取到指令寄存器里面執(zhí)行,然后根據(jù)指令長(zhǎng)度自增,開(kāi)始順序讀取下一條指令。可以看到,一個(gè)程序的一條條指令,在內(nèi)存里面是連續(xù)保存的,也會(huì)一條條順序加載。
現(xiàn)在就來(lái)看一個(gè)包含if…else的簡(jiǎn)單程序。
// test.c#include #include int main(){srand(time(NULL));int r = rand() % 2;int a = 10;if (r == 0){a = 1;} else {a = 2;}
把這個(gè)程序編譯成匯編代碼。
if (r == 0)3b:83 7d fc 00 cmpDWORD PTR [rbp-0x4],0x03f:75 09jne4a {a = 1;41:c7 45 f8 01 00 00 00movDWORD PTR [rbp-0x8],0x148:eb 07jmp51 }else{a = 2;4a:c7 45 f8 02 00 00 00movDWORD PTR [rbp-0x8],0x251:b8 00 00 00 00moveax,0x0}
可以看到,這里對(duì)于r == 0的條件判斷,被編譯成了cmp和jne這兩條指令。對(duì)于:
cmpDWORD PTR [rbp-0x4],0x0
cmp指令比較了前后兩個(gè)操作數(shù)的值,這里的DWORD PTR代表操作的數(shù)據(jù)類(lèi)型是32位的整數(shù),而[rbp-0x4]則是一個(gè)寄存器的地址。所以,第一個(gè)操作數(shù)就是從寄存器里拿到的變量r的值。第二個(gè)操作數(shù)0x0就是我們?cè)O(shè)定的常量0的16進(jìn)制表示。cmp指令的比較結(jié)果,會(huì)存入到條件碼寄存器當(dāng)中去。
在這里,如果比較的結(jié)果是False,也就是0,就把零標(biāo)志條件碼(對(duì)應(yīng)的條件碼是ZF,Zero Flag)設(shè)置為1。
cmp指令執(zhí)行完成之后,PC寄存器會(huì)自動(dòng)自增,開(kāi)始執(zhí)行下一條jne的指令。
對(duì)于:
jne4a
jne指令,是jump if not equal的意思,它會(huì)查看對(duì)應(yīng)的零標(biāo)志位。如果為0,會(huì)跳轉(zhuǎn)到后面跟著的操作數(shù)4a的位置。這個(gè)4a,對(duì)應(yīng)這里匯編代碼的行號(hào),也就是上面設(shè)置的else條件里的第一條指令。
當(dāng)跳轉(zhuǎn)發(fā)生的時(shí)候,PC寄存器就不再是自增變成下一條指令的地址,而是被直接設(shè)置成這里的4a這個(gè)地址。這個(gè)時(shí)候,CPU再把4a地址里的指令加載到指令寄存器中來(lái)執(zhí)行。
4a:c7 45 f8 02 00 00 00movDWORD PTR [rbp-0x8],0x251:b8 00 00 00 00moveax,0x0
4a的指令,實(shí)際是一條mov指令,第一個(gè)操作數(shù)和前面的cmp指令一樣,是另一個(gè)32位整型的寄存器地址,以及對(duì)應(yīng)的2的16進(jìn)制值0x2。mov指令把2設(shè)置到對(duì)應(yīng)的寄存器里去,相當(dāng)于一個(gè)賦值操作。然后,PC寄存器里的值繼續(xù)自增,執(zhí)行下一條mov指令。
下一條指令也是mov,第一個(gè)操作數(shù)eax,代表累加寄存器,第二個(gè)操作數(shù)0x0則是16進(jìn)制的0的表示。這條指令其實(shí)沒(méi)有實(shí)際的作用,它的作用是一個(gè)占位符。
我們先來(lái)看個(gè)例子:
// function_example.c#include int static add(int a, int b){return a+b;}int main(){int x = 5;int y = 10;int u = add(x, y);}
我們把這個(gè)程序編譯之后:
int static add(int a, int b){0:55pushrbp1:48 89 e5movrbp,rsp4:89 7d fcmovDWORD PTR [rbp-0x4],edi7:89 75 f8movDWORD PTR [rbp-0x8],esireturn a+b;a:8b 55 fcmovedx,DWORD PTR [rbp-0x4]d:8b 45 f8moveax,DWORD PTR [rbp-0x8]10:01 d0addeax,edx}12:5dpoprbp13:c3ret0000000000000014 :int main(){14:55pushrbp15:48 89 e5movrbp,rsp18:48 83 ec 10 subrsp,0x10int x = 5;1c:c7 45 fc 05 00 00 00movDWORD PTR [rbp-0x4],0x5int y = 10;23:c7 45 f8 0a 00 00 00movDWORD PTR [rbp-0x8],0xaint u = add(x, y);2a:8b 55 f8movedx,DWORD PTR [rbp-0x8]2d:8b 45 fcmoveax,DWORD PTR [rbp-0x4]30:89 d6movesi,edx32:89 c7movedi,eax34:e8 c7 ff ff ffcall0 39:89 45 f4movDWORD PTR [rbp-0xc],eax3c:b8 00 00 00 00moveax,0x0}41:c9leave42:c3ret
在add函數(shù)編譯之后,代碼先執(zhí)行了一條push指令和一條mov指令;在函數(shù)執(zhí)行結(jié)束的時(shí)候,又執(zhí)行了一條pop和一條ret指令。
add函數(shù)的第0行,push rbp這個(gè)指令,就是在進(jìn)行壓棧。這里的rbp又叫棧幀指針(Frame Pointer),是一個(gè)存放了當(dāng)前棧幀位置的寄存器。push rbp就把之前調(diào)用函數(shù)的返回地址,壓到棧頂。
接著,第1行的一條命令mov rbp, rsp里,則是把rsp這個(gè)棧指針(Stack Pointer)的值復(fù)制到rbp里,而rsp始終會(huì)指向棧頂。這個(gè)命令意味著,rbp這個(gè)棧幀指針指向的返回地址,變成當(dāng)前最新的棧頂,也就是add函數(shù)的返回地址了。
而在函數(shù)add執(zhí)行完成之后,又會(huì)分別調(diào)用第12行的pop rbp來(lái)將當(dāng)前的棧頂出棧,然后調(diào)用第13行的ret指令,將程序的控制權(quán)返回到出棧后的棧頂,也就是main函數(shù)的返回地址。
實(shí)際上,“C語(yǔ)言代碼-匯編代碼-機(jī)器碼” 這個(gè)過(guò)程,在我們的計(jì)算機(jī)上進(jìn)行的時(shí)候是由兩部分組成的。
第一個(gè)部分由編譯(Compile)、匯編(Assemble)以及鏈接(Link)三個(gè)階段組成。在這三個(gè)階段完成之后,我們就生成了一個(gè)可執(zhí)行文件。
第二部分,我們通過(guò)裝載器(Loader)把可執(zhí)行文件裝載(Load)到內(nèi)存中。CPU從內(nèi)存中讀取指令和數(shù)據(jù),來(lái)開(kāi)始真正執(zhí)行程序。
程序的鏈接,是把對(duì)應(yīng)的不同文件內(nèi)的代碼段,合并到一起,成為最后的可執(zhí)行文件。
在可執(zhí)行文件里,我們可以看到,對(duì)應(yīng)的函數(shù)名稱(chēng),像add、main等等,乃至你自己定義的全局可以訪問(wèn)的變量名稱(chēng)對(duì)應(yīng)的地址,存儲(chǔ)在一個(gè)叫作符號(hào)表(Symbols Table)的位置里。符號(hào)表相當(dāng)于一個(gè)地址簿,把名字和地址關(guān)聯(lián)了起來(lái)。
經(jīng)過(guò)程序的鏈接之后,main函數(shù)里調(diào)用add的跳轉(zhuǎn)地址,不再是下一條指令的地址了,而是add函數(shù)的入口地址了。
鏈接器會(huì)掃描所有輸入的目標(biāo)文件,然后把所有符號(hào)表里的信息收集起來(lái),構(gòu)成一個(gè)全局的符號(hào)表。然后再根據(jù)重定位表,把所有不確定要跳轉(zhuǎn)地址的代碼,根據(jù)符號(hào)表里面存儲(chǔ)的地址,進(jìn)行一次修正。最后,把所有的目標(biāo)文件的對(duì)應(yīng)段進(jìn)行一次合并,變成了最終的可執(zhí)行代碼。
這個(gè)合并代碼段的方法,是叫靜態(tài)鏈接。
在動(dòng)態(tài)鏈接的過(guò)程中,我們想要“鏈接”的,不是存儲(chǔ)在硬盤(pán)上的目標(biāo)文件代碼,而是加載到內(nèi)存中的共享庫(kù)(Shared Libraries)。
要想要在程序運(yùn)行的時(shí)候共享代碼,也有一定的要求,就是這些機(jī)器碼必須是“地址無(wú)關(guān)”的。換句話說(shuō)就是,這段代碼,無(wú)論加載在哪個(gè)內(nèi)存地址,都能夠正常執(zhí)行。
動(dòng)態(tài)代碼庫(kù)內(nèi)部的變量和函數(shù)調(diào)用都是使用相對(duì)地址。因?yàn)檎麄€(gè)共享庫(kù)是放在一段連續(xù)的虛擬內(nèi)存地址中的,無(wú)論裝載到哪一段地址,不同指令之間的相對(duì)地址都是不變的。
在運(yùn)行這些可執(zhí)行文件的時(shí)候,我們其實(shí)是通過(guò)一個(gè)裝載器,解析ELF或者PE格式的可執(zhí)行文件。裝載器會(huì)把對(duì)應(yīng)的指令和數(shù)據(jù)加載到內(nèi)存里面來(lái),讓CPU去執(zhí)行。
裝載器需要滿(mǎn)足兩個(gè)要求:
基于上面,我們需要在內(nèi)存空間地址和整個(gè)程序指令指定的內(nèi)存地址做一個(gè)映射。
把指令里用到的內(nèi)存地址叫作虛擬內(nèi)存地址(Virtual Memory Address),實(shí)際在內(nèi)存硬件里面的空間地址,我們叫物理內(nèi)存地址(Physical Memory Address)。
分頁(yè)是把整個(gè)物理內(nèi)存空間切成一段段固定尺寸的大小。而對(duì)應(yīng)的程序所需要占用的虛擬內(nèi)存空間,也會(huì)同樣切成一段段固定尺寸的大小。這樣一個(gè)連續(xù)并且尺寸固定的內(nèi)存空間,我們叫頁(yè)(Page)。
從虛擬內(nèi)存到物理內(nèi)存的映射,不再是拿整段連續(xù)的內(nèi)存的物理地址,而是按照一個(gè)一個(gè)頁(yè)來(lái)的。
分頁(yè)之后避免了整個(gè)程序和硬盤(pán)進(jìn)行交換而產(chǎn)生性能瓶頸。即使內(nèi)存空間不夠,需要讓現(xiàn)有的、正在運(yùn)行的其他程序,通過(guò)內(nèi)存交換釋放出一些內(nèi)存的頁(yè)出來(lái),一次性寫(xiě)入磁盤(pán)的也只有少數(shù)的一個(gè)頁(yè)或者幾個(gè)頁(yè),不會(huì)花太多時(shí)間,讓整個(gè)機(jī)器被內(nèi)存交換的過(guò)程給卡住。
現(xiàn)在手機(jī)運(yùn)行內(nèi)存已經(jīng)非常夸張了,16G的運(yùn)行內(nèi)存已經(jīng)出來(lái)了,而且各家的旗艦手機(jī)的頂配版本都標(biāo)配16+512G超大內(nèi)存組合了 。但是普通人買(mǎi)手機(jī)還在考慮8G和12G的運(yùn)行內(nèi)存,我們也想嘗試一下16G運(yùn)行...
2025.07.03最新的Windows 11系統(tǒng)最低配置要求是1G的64位處理器,這說(shuō)明微軟已經(jīng)完全放棄32位系統(tǒng)架構(gòu)全面轉(zhuǎn)向64位系統(tǒng)時(shí)代了。內(nèi)存最低要求4GB,而WIN10最低要求是1G,提升了四倍,雖然我們都知道...
2025.07.03運(yùn)行內(nèi)存是指手機(jī)運(yùn)行程序時(shí)的內(nèi)存,也叫RAM(簡(jiǎn)稱(chēng)運(yùn)存)。而另一個(gè)內(nèi)存是用來(lái)存儲(chǔ)東西的內(nèi)存,就像8G的MP4一樣,它擁有8G的存儲(chǔ)空間,這種內(nèi)存為一般叫的手機(jī)內(nèi)存。手機(jī)的“內(nèi)存”通常指“運(yùn)行內(nèi)存”及“...
2025.06.27我的nas是威聯(lián)通453d mini 8GB版,我啟用了container station容器工作站,也就是docker功能,還啟用了Virtualization Station虛擬化工作站功能。配置...
2025.06.29隨著科技的不斷發(fā)展,我們對(duì)于電腦內(nèi)存的需求越來(lái)越高。當(dāng)我們發(fā)現(xiàn)電腦內(nèi)存不足時(shí),我們需要拓展內(nèi)存。下面,本文將介紹如何拓展電腦內(nèi)存。一、了解電腦內(nèi)存的基礎(chǔ)知識(shí)在拓展電腦內(nèi)存之前,我們需要先了解電腦內(nèi)存的...
2025.07.03