ARM MMU工作原理剖析[轉]

一、MMU的產生

??????許多年以前,當人們還在使用DOS或是更古老的操作系統的時候,計算機的內存還非常小,一般都是以K為單位進行計算,相應的,當時的程序規模也不大,所以內存容量雖然小,但還是可以容納當時的程序。但隨著圖形界面的興起還用用戶需求的不斷增大,應用程序的規模也隨之膨脹起來,終于一個難題出現在程序員的面前,那就是應用程序太大以至于內存容納不下該程序,通常解決的辦法是把程序分割成許多稱為覆蓋塊(overlay)的片段。覆蓋塊0首先運行,結束時他將調用另一個覆蓋塊。雖然覆蓋塊的交換是由OS完成的,但是必須先由程序員把程序先進行分割,這是一個費時費力的工作,而且相當枯燥。人們必須找到更好的辦法從根本上解決這個問題。不久人們找到了一個辦法,這就是虛擬存儲器(virtual memory).虛擬存儲器的基本思想是程序,數據,堆棧的總的大小可以超過物理存儲器的大小,操作系統把當前使用的部分保留在內存中,而把其他未被使用的部分保存在磁盤上比如對一個16MB的程序和一個內存只有4MB的機器,OS通過選擇,可以決定各個時刻將哪4M的內容保留在內存中,并在需要時在內存和磁盤間交換程序片段,這樣就可以把這個16M的程序運行在一個只具有4M內存機器上了。而這個16M的程序在運行前不必由程序員進行分割。


????? 任何時候,計算機上都存在一個程序能夠產生的地址集合,我們稱之為地址范圍。這個范圍的大小由CPU的位數決定,例如一個32位的CPU,它的地址范圍是0~0xFFFFFFFF (4G)而對于一個64位的CPU,它的地址范圍為0~0xFFFFFFFFFFFFFFFF (64T),這個范圍就是我們的程序能夠產生的地址范圍,我們把這個地址范圍稱為虛擬地址空間,該空間中的某一個地址我們稱之為虛擬地址。與虛擬地址空間和虛擬地址相對應的則是物理地址空間和物理地址,大多數時候我們的系統所具備的物理地址空間只是虛擬地址空間的一個子集,這里舉一個最簡單的例子直觀地說明這兩者,對于一臺內存為256MB的32bit x86主機來說,它的虛擬地址空間范圍是0~0xFFFFFFFF(4G),而物理地址空間范圍是0x000000000~0x0FFFFFFF(256MB)。


????? 在沒有使用虛擬存儲器的機器上,虛擬地址被直接送到內存總線上,使具有相同地址的物理存儲器被讀寫。而在使用了虛擬存儲器的情況下,虛擬地址不是被直接送到內存地址總線上,而是送到內存管理單元——MMU(主角終于出現了)。他由一個或一組芯片組成,一般存在與協處理器中,其功能是把虛擬地址映射為物理地址。

?

二、MMU工作過程

????? 大多數使用虛擬存儲器的系統都使用一種稱為分頁(paging)。虛擬地址空間劃分成稱為頁(page)的單位,而相應的物理地址空間也被進行劃分,單位是頁框().頁和頁框的大小必須相同。接下來配合圖片我以一個例子說明頁與頁框之間在MMU的調度下是如何進行映射的:

????? 在這個例子中我們有一臺可以生成16位地址的機器,它的虛擬地址范圍從0x0000~0xFFFF(64K),而這臺機器只有32K的物理地址,因此他可以運行64K的程序,但該程序不能一次性調入內存運行。這臺機器必須有一個達到可以存放64K程序的外部存儲器(例如磁盤或是FLASH)以保證程序片段在需要時可以被調用。在這個例子中,頁的大小為4K,頁框大小與頁相同(這點是必須保證的,內存和外圍存儲器之間的傳輸總是以頁為單位的),對應64K的虛擬地址和32K的物理存儲器,他們分別包含了16個頁和8個頁框。


????? 我們先根據上圖解釋一下分頁后要用到的幾個術語,在上面我們已經接觸了頁和頁框,上圖中綠色部分是物理空間,其中每一格表示一個物理頁框。橘黃色部分是虛擬空間,每一格表示一個頁,它由兩部分組成,分別是 Index(頁框索引)和位p(present 存在位), Index的意義很明顯,它指出本頁是往哪個物理頁框進行映射的,位p的意義則是指出本頁的映射是否有效,如上圖,當某個頁并沒有被映射時(或稱映射無效, Index部分為X),該位為0,映射有效則該位為1。


????我們執行下面這些指令(本例子的指令不針對任何特定機型,都是偽指令)
例1:
??? MOVE REG,0 //將0號地址的值傳遞進寄存器REG.
????虛擬地址0將被送往MMU,MMU看到該虛地址落在頁0范圍內(頁0范圍是0到4095),從上圖我們看到頁0所對應(映射)的頁框為2(頁框2的地址范圍是8192到12287),因此MMU將該虛擬地址轉化為物理地址8192,并把地址8192送到地址總線上。內存對MMU的映射一無所知,它只看到一個對地址8192的讀請求并執行它。MMU從而把0到4096的虛擬地址映射到8192到12287的物理地址。


例2:
??? MOVE REG,8192
??? 被轉換為
??? MOVE REG,24576?
??? 因為虛擬地址8192在頁2中,而頁2被映射到頁框6(物理地址從24576到28671)


例3:
??? MOVE REG,20500
??? 被轉換為
??? MOVE REG,12308
??? 虛擬地址20500在虛頁5(虛擬地址范圍是20480到24575)距開頭20個字節處,虛頁5映射到頁框3(頁框3的地址范圍是 12288到16383),于是被映射到物理地址12288+20=12308。


????? 通過適當的設置MMU,可以把16個虛頁隱射到8個頁框中的任何一個,但是這個方法并沒有有效的解決虛擬地址空間比物理地址空間大的問題。從上圖中我們可以看到,我們只有8個頁框(物理地址),但我們有16個頁(虛擬地址),所以我們只能把16個頁中的8個進行有效的映射。我們看看例4會發生什么情況

????? MOV REG,32780
????? 虛擬地址32780落在頁8的范圍內,從上圖總我們看到頁8沒有被有效的進行映射(該頁被打上X),這是又會發生什么?MMU注意到這個頁沒有被映射,于是通知CPU發生一個缺頁故障(page fault).這種情況下操作系統必須處理這個頁故障,它必須從8個物理頁框中找到1個當前很少被使用的頁框并把該頁框的內容寫入外圍存儲器(這個動作被稱為page copy),隨后把需要引用的頁(例4中是頁8)映射到剛才釋放的頁框中(這個動作稱為修改映射關系),然后從新執行產生故障的指令(MOV REG,32780)。假設操作系統決定釋放頁框1,那么它將把虛頁8裝入物理地址的4-8K,并做兩處修改:首先把標記虛頁1未被映射(原來虛頁1是被影射到頁框1的),以使以后任何對虛擬地址4K到8K的訪問都引起頁故障而使操作系統做出適當的動作(這個動作正是我們現在在討論的),其次他把虛頁8對應的頁框號由X變為1,因此重新執行MOV REG,32780時,MMU將把32780映射為4108。


????? 我們大致了解了MMU在我們的機器中扮演了什么角色以及它基本的工作內容是什么,下面我們將舉例子說明它究竟是如何工作的(注意,本例中的MMU并無針對某種特定的機型,它是所有MMU工作的一個抽象)。


????? 首先明確一點,MMU的主要工作只有一個,就是把虛擬地址映射到物理地址。
我們已經知道,大多數使用虛擬存儲器的系統都使用一種稱為分頁(paging)的技術,就象我們剛才所舉的例子,虛擬地址空間被分成大小相同的一組頁,每個頁有一個用來標示它的頁號(這個頁號一般是它在該組中的索引,這點和C/C++中的數組相似)。在上面的例子中0~4K的頁號為0,4~8K的頁號為1,8~12K的頁號為2,以此類推。而虛擬地址(注意:是一個確定的地址,不是一個空間)被MMU分為2個部分,第一部分是頁號索引(page Index),第二部分則是相對該頁首地址的偏移量(offset). 。我們還是以剛才那個16位機器結合下圖進行一個實例說明,該實例中,虛擬地址8196被送進MMU,MMU把它映射成物理地址。16位的CPU總共能產生的地址范圍是0~64K,按每頁4K的大小計算,該空間必須被分成16個頁。而我們的虛擬地址第一部分所能夠表達的范圍也必須等于16(這樣才能索引到該頁組中的每一個頁),也就是說這個部分至少需要4個bit。一個頁的大小是4K(4096),也就是說偏移部分必須使用12個bit來表示(2^12=4096,這樣才能訪問到一個頁中的所有地址),8196的二進制碼如下圖所示:

????? 該地址的頁號索引為0010(二進制碼),既索引的頁為頁2,第二部分為000000000100(二進制),偏移量為4。頁2中的頁框號為6(頁2映射在頁框6,見上圖),我們看到頁框6的物理地址是24~28K。于是MMU計算出虛擬地址8196應該被映射成物理地址24580(頁框首地址+偏移量=24576+4=24580)。同樣的,若我們對虛擬地址1026進行讀取,1026的二進制碼為0000010000000010,page index="0000"=0,offset=010000000010=1026。頁號為0,該頁映射的頁框號為2,頁框2的物理地址范圍是8192~12287,故MMU將虛擬地址1026映射為物理地址9218(頁框首地址+偏移量=8192+1026=9218)。以上就是MMU的工作過程。

三、S3C24XX的MMU工作過程


????下面我們針對s3c2410的MMU(注1)進行講解。
??? S3c2410總共有4種內存映射方式,分別是:
??? 1.Fault (無映射)
??? 2.Coarse Page (粗表)
??? 3.Section (段)
??? 4.Fine Page (細表)
??? 我們以Section(段)進行說明。
??? ARM920T是一個32bit的CPU,它的虛擬地址空間為2^32=4G。而在Section模式,這4G的虛擬空間被分成一個一個稱為段(Section)的單位(與我們上面講的頁在本質上其實是一致的),每個段的長度是1M (而我們之前所使用的頁的長度是4K)。4G的虛擬內存總共可以被分成4096個段(1M*4096=4G),因此我們必須用4096個描述符來對這組段進行描述,每個描述符占用4個Byte,故這組描述符的大小為16KB (4byte*4096),這4096個描述符構為一個表格,我們稱其為Tralaton Table.

??? 上圖是描述符的結構
??? Section base address:段基地址(相當于頁框號首地址)
??? AP: 訪問控制位Access Permission
??? Domain: 訪問控制寄存器的索引。Domain與AP配合使用,對訪問權限進行檢查
??? C:當C被置1時為write-through (WT)模式
??? B: 當B被置1時為write-back (WB)模式(C,B兩個位在同一時刻只能有一個被置1)
??? 下面是s3c2410內存映射后的一個示意圖:

????? 我的s3c2410上配置的SDRSAM大小為64M,該SDRAM的物理地址范圍是0x3000 0000~0x33FF FFFF(屬于Bank 6),由于1個Section的大小是1M,所以該物理空間可以被分成64個物理段(頁框).


????? 在Section模式下,送進MMU的虛擬地址(注1)被分為兩部分(這點和我們上面舉的例子是一樣的),這兩部分為 Deor Index(相當于上面例子的Page Index)和 Offset,de index長度為12bit(2^12=4096,從這個關系式你能看出什么?:) ),Offset長度為20bit(2^20=1M,你又能看出什么?:)).觀察一下一個描述符(Deor)中的Section Base Address部分,它長度為12 bit,里面的值是該虛擬段(頁)映射成的物理段(頁框)的物理地址前12bit,由于每一個物理段的長度都是1M,所以物理段首地址的后20bit總是為0x00000(每個Section都是以1M對齊),確定一個物理地址的方法是 物理頁框基地址+虛擬地址中的偏移部分=Section Base Address<<20+Offset ,呵呵,可能你有點糊涂了,還是舉一個實際例子說明吧。

????? 假設現在執行指令MOV REG, 0x30000012,虛擬地址的二進制碼為00110000 00000000 00000000 00010010,前12位是Deor Index= 00110000 0000=768,故在Translation Table里面找到第768號描述符,該描述的Section Base Address="0x0300",也就是說描述符所描述的虛擬段(頁)所映射的物理段(頁框)的首地址為0x3000 0000(物理段(頁框)的基地址=Section Base Address左移20bit=0x0300<<20=0x3000 0000),而Offset=000000 00000000 00010010=0x12,故虛擬地址0x30000012映射成的物理地址=0x3000 0000+0x12=0x3000 0012(物理頁框基地址+虛擬地址中的偏移)。你可能會問怎么這個虛擬地址和映射后的物理地址一樣?這是由我們定義的映射規則所決定的。在這個例子中我們定義的映射規則是把虛擬地址映射成和他相等的物理地址。我們這樣書寫映射關系的代碼:
void mem_mapping_linear(void)
{
??? unsigned long deor_index, section_base, sdram_base, sdram_size;
??? sdram_base=0x30000000;
??? sdram_size=0x 4000000;
??? for (section _base= sdram_base,deor_index = section _base>>20;
???????? section _base < sdram_base+ sdram_size;?
???????? deor_index+=1;section _base +=0x100000)
??? {
???????? *(mmu_tlb_base + (deor_index)) = (section _base>>20) | MMU_OTHER_SECDESC;
??? }
}


????? 上面的這段段代碼把虛擬空間0x3000 0000~0x33FF FFFF映射到物理空間0x3000 0000~0x33FF FFFF,由于虛擬空間與物理空間空間相吻合,所以虛擬地址與他們各自對應的物理地址在值上是一致的。當初始完Translation Table之后,記得要把Translation Table的首地址(第0號描述符的地址)加載進協處理器CP15的Control Register2(2號控制寄存器)中,該控制寄存器的名稱叫做Translation table base (TTB) register。


????? 以上討論的是deor中的Section Base Address以及虛擬地址和物理地址的映射關系,然而MMU還有一個重要的功能,那就是訪問控制機制(Access Permission )。簡單說訪問控制機制就是CPU通過某種方法判斷當前程序對內存的訪問是否合法(是否有權限對該內存進行訪問),如果當前的程序并沒有權限對即將訪問的內存區域進行操作,則CPU將引發一個異常,s3c2410稱該異常為Permission fault,x86架構則把這種異常稱之為通用保護異常(General Protection),什么情況會引起Permission fault呢?比如處于User級別的程序要對一個System級別的內存區域進行寫操作,這種操作是越權的,應該引起一個Permission fault,搞過x86架構的朋友應該聽過保護模式(Protection Mode),保護模式就是基于這種思想進行工作的,于是我們也可以這么說:s3c2410的訪問控制機制其實就是一種保護機制。那s3c2410的訪問控制機制到底是由什么元素去參與完成的呢?它們間是怎么協調工作的呢?這些元素總共有:
??? 1.協處理器CP15中Control Register3:DOMAIN ACCESS CONTROL REGISTER?
??? 2.段描述符中的AP位和Domain位
??? 3.協處理器CP15中Control Register1(控制寄存器1)中的S bit和R bit?
??? 4.協處理器CP15中Control Register5(控制寄存器5)
??? 5.協處理器CP15中Control Register6(控制寄存器6)
??? DOMAIN ACCESS CONTROL REGISTER 是訪問控制寄存器,該寄存器有效位為32,被分成16個區域,每個區域由兩個位組成,他們說明了當前內存的訪問權限檢查的級別,如下圖所示:


????? 每區域可以填寫的值有4個,分別為00,01,10,11(二進制),他們的意義如下所示:


??? 00:當前級別下,該內存區域不允許被訪問,任何的訪問都會引起一個domain fault
??? 01:當前級別下,該內存區域的訪問必須配合該內存區域的段描述符中AP位進行權檢查
??? 10:保留狀態(我們最好不要填寫該值,以免引起不能確定的問題)
??? 11:當前級別下,對該內存區域的訪問都不進行權限檢查。
????? 我們再來看看dior中的Domain區域,該區域總共有4個bit,里面的值是對DOMAIN ACCESS CONTROL REGISTER中16個區域的索引.而AP位配合S bit和A bit對當前描述符描述的內存區域被訪問權限的說明,他們的配合關系如下圖所示:


??? AP位也是有四個值,我結合實例對其進行說明.
??? 在下面的例子中,我們的DOMAIN ACCESS CONTROL REGISTER都被初始化成0xFFFF BDCF,如下圖所示:


例1:
Dior 中的domain=4,AP=10(這種情況下S bit ,A bit 被忽略)
假設現在我要對該描述符描述的內存區域進行訪問:
由于domain=4,而DOMAIN ACCESS CONTROL REGISTER中field 4的值是01,系統會對該訪問進行訪問權限的檢查。
假設當前CPU處于Supervisor模式下,則程序可以對該描述符描述的內存區域進行讀寫操作。
假設當前CPU處于User模式下,則程序可以對該描述符描述的內存進行讀訪問,若對其進行寫操作則引起一個permission fault.

例2:
Dior 中的domain=0,AP=10(這種情況下S bit ,A bit 被忽略)
domain=0,而DOMAIN ACCESS CONTROL REGISTER中field 0的值是11,系統對任何內存區域的訪問都不進行訪問權限的檢查。
由于統對任何內存區域的訪問都不進行訪問權限的檢查,所以無論CPU處于合種模式下(Supervisor模式或是User模式),程序對該描述符描述的內存都可以順利地進行讀寫操作

例3:Dior 中的domain=4,AP=11(這種情況下S bit ,A bit 被忽略)
由于domain=4,而DOMAIN ACCESS CONTROL REGISTER中field 4的值是01,系統會對該訪問進行訪問權限的檢查。
由于AP=11,所以無論CPU處于合種模式下(Supervisor模式或是User模式),程序對該描述符描述的內存都可以順利地進行讀寫操作

例4:
Dior 中的domain=4,AP=00, S bit="0",A bit="0"
由于domain=4,而DOMAIN ACCESS CONTROL REGISTER中field 4的值是01,系統會對該訪問進行訪問權限的檢查。
由于AP=00,S bit="0",A bit="0",所以無論CPU處于合種模式下(Supervisor模式或是User模式),程序對該描述符描述的內存都只能進行讀操作,否則引起permission fault.
通過以上4個例子我們得出兩個結論:
1.對某個內存區域的訪問是否需要進行權限檢查是由該內存區域的描述符中的Domain域決定的。
2.某個內存區域的訪問權限是由該內存區域的描述符中的AP位和協處理器CP15中Control Register1(控制寄存器1)中的S bit和R bit所決定的。

轉載于:https://www.cnblogs.com/chenzk/p/3371055.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/377704.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/377704.shtml
英文地址,請注明出處:http://en.pswp.cn/news/377704.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

棧與隊列在SGI STL的底層實現

棧 棧提供push和pop等接口&#xff0c;不提供走訪功能&#xff0c;也不提供迭代器。 STL中棧不被歸類為容器&#xff0c;而被歸類為container adapter(容器適配器)&#xff0c;這是因為棧是以底層容器完成其所有的工作&#xff0c;對外提供統一的接口&#xff0c;底層容器是可…

【原創】SharePoint Document library List Check out 文檔時碰到的問題解決

環境&#xff1a;TFS(Team Foundation Server)集成的WSS 3.0&#xff08;SharePoint Service 3.0&#xff09; 問題&#xff1a;如題&#xff0c;祥見下圖 解決&#xff1a;一般碰到沒有經驗的問題&#xff0c;大家當然是外事不決問谷歌了&#xff0c;于是谷歌搜到了這篇博客 h…

getdate函數_PHP getdate()函數與示例

getdate函數PHP getdate()函數 (PHP getdate() function) getdate() function is used to get the local date/time (or it is also used to get the date/time based on the given timestamp. getdate()函數用于獲取本地日期/時間(或也用于根據給定的時間戳獲取日期/時間。 S…

四、入庫管理功能的完善

一、數據庫的創建 在fiber_yy數據庫下創建yy_textile表 先隨便添加幾條數據 二、頁面的完善 登錄注冊頁面我就不演示了&#xff0c;前幾篇博文也都有介紹 warehousing入庫頁面 main_page頁面進行功能完善 三、代碼實現 warehousing頁面 using System; using System.…

leetcode 232. 用棧實現隊列 思考分析

題目 請你僅使用兩個棧實現先入先出隊列。隊列應當支持一般隊列的支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 實現 MyQueue 類&#xff1a; void push(int x) 將元素 x 推到隊列的末尾 int pop() 從隊列的開頭移除并返回元素 int peek() 返…

YCSB初步介紹

隨著大數據時代的到來和云計算的不斷發展&#xff0c;作為云計算最基礎的設施存儲產品也越來越多&#xff0c;開源分布式存儲系統有BigTable-like系統HBase&#xff0c;dynamo-like系統Cassandra&#xff0c;voldemort&#xff0c;Riak&#xff0c;淘寶開源的OceanBase等。當然…

kotlin實現繼承_Kotlin程序| 繼承的例子

kotlin實現繼承遺產 (Inheritance) Inheritance is a mechanism wherein a new class is derived from an existing class. 繼承是一種機制&#xff0c;其中新類是從現有類派生的。 All Kotlin Classes have a common Superclass Any, it is the Default Superclass with no S…

【C++grammar】動態類型轉換、typeid與RTTI

目錄動態類型轉換1、為何需要動態類型轉換2、dynamic_cast<>();運算符3、向上轉換和向下轉換( Upcasting and Downcasting)4、 基類對象和派生類對象的互操作5、Upcasting/Downcasting與繼承鏈上不同類的對象之間的賦值有什么關系和區別&#xff1f;typeid 運行時查詢類型…

nginx資源定向 css js路徑問題

今天玩玩項目&#xff0c;學學nginx發現還不錯&#xff0c;速度還可以&#xff0c;但是CSS JS確無法使用&#xff0c;原來Iginx配置時需要對不同類型的文件配置規則&#xff0c;真是很郁悶&#xff0c;不過想想也還是很有道理。閑暇之際&#xff0c;把配置貼上來。#user nobody…

五、庫存查詢功能的完善

一、數據庫的建立 由于查詢功能和之前的 入庫管理功能 所用的數據庫都一樣&#xff0c;這里仍使用yy_textile表 在fiber_yy數據庫下創建yy_textile表 初始數據庫信息 二、頁面的完善 登錄注冊頁面我就不演示了&#xff0c;前幾篇博文也都有介紹 query查詢頁面 main_page…

整合ajaxmin 和 less 到VS.net

我用的前端框架是bootstrap_extra, twitter團隊做的&#xff0c;這個是他的一個擴展&#xff0c;首先從上面下載一個。至于ajaxmin&#xff0c;請參考這里1) 從bootstrap_extra的解壓包中&#xff0c;復制build目錄下三個文件到項目中去&#xff0c;這三個文件分別是BatchSubsi…

轉:只能選擇GridView中的一個CheckBox(單選CheckBox)

方法1&#xff1a; protected void GridView2_RowDataBound(object sender, GridViewRowEventArgs e){CheckBox cbx e.Row.FindControl("cbID") as CheckBox;try{//綁定選中CheckBox 客戶端IDcbx.Attributes.Add("onclick", "Change(" cbx.Cli…

六、出庫管理功能的實現

一、數據庫的建立 這里仍使用yy_textile表 在fiber_yy數據庫下創建yy_textile表 初始數據庫信息 二、頁面的完善 登錄注冊頁面我就不演示了&#xff0c;前幾篇博文也都有介紹 shipment出庫管理頁面 main_page頁面進行功能完善 三、代碼實現 shipment出庫管理頁面 u…

數學建模:層次分析法實例以及代碼

博主聯系方式&#xff1a; QQ:1540984562 QQ交流群&#xff1a;892023501 群里會有往屆的smarters和電賽選手&#xff0c;群里也會不時分享一些有用的資料&#xff0c;有問題可以在群里多問問。 目錄層次分析法的思想層次分析法步驟具體案例(市政工程項目建設決策)1.問題提出2.…

c 僵尸進程_演示僵尸進程的C程序

c 僵尸進程僵尸進程 (Zombie process) A process which has finished its execution but still has an entry in the process table to report to its parent process is known as a zombie process. 一個已經完成執行但仍在進程表中具有要報告給其父進程的條目的進程稱為僵尸進…

探秘IntelliJ IDEA 13測試版新功能——調試器顯示本地變量

IntelliJ IDEA在業界被公認為最好的Java開發平臺之一&#xff0c;JetBrains公司將在12月正式發布IntelliJ IDEA 13版本。 現在&#xff0c;小編將和大家一起探秘密IntelliJ IDEA 13測試版本新功能——調試器顯示本地變量。這個功能非常強大&#xff0c;調試器可以顯示變量&…

C# Windows Form下的控件的Validator(數據驗證)

由于偶爾的一個想法&#xff0c;謀生了一個做一個windows form下的Validator控件&#xff0c;或者直接說類吧&#xff01; 因為webform下的Validator控件太好用了。哈哈&#xff0c;直接看代碼&#xff01; 下面這個類&#xff0c;主要是一個簡單的驗證類&#xff0c;不過只是起…

七、流水查詢---記錄用戶登錄信息

一、數據庫的建立 在fiber_yy數據庫下創建yy_user_record表 可以先手動填入幾條數據信息 初始數據庫信息 username為用戶賬號 sex為用戶注冊所填寫的性別 phone為用戶手機號 time為用戶登錄該系統的時間 二、頁面的設計 登錄注冊頁面我就不演示了&#xff0c;前幾篇博文…

leetcode 455. 分發餅干 思考分析

目錄題目自己的思路以及AC代碼參考思路題目 假設你是一位很棒的家長&#xff0c;想要給你的孩子們一些小餅干。但是&#xff0c;每個孩子最多只能給一塊餅干。 對每個孩子 i&#xff0c;都有一個胃口值 g[i]&#xff0c;這是能讓孩子們滿足胃口的餅干的最小尺寸&#xff1b;并…

c++ cdi+示例_C ++'not'關鍵字和示例

c cdi示例"not" is an inbuilt keyword that has been around since at least C98. It is an alternative to ! (Logical NOT) operator and it mostly uses with the conditions. “ not”是一個內置關鍵字&#xff0c;至少從C 98起就存在。 它是替代&#xff01; …