一、查看内存分布情况
设置“页目录表”和“页表”之前,最好先查看下内存分布情况,根据“OS可用内存的大小”来设置她们;否则可能设置了太大的“页目录表”和“页表”而浪费了宝贵的内存。
如果傻乎乎地设置“页目录表”和“页表”,我们来看看后果:
假设内存的一个物理块是4KB(=4096B)。我们知道,“页目录表”占用一个内存物理块,而“页目录表”中的每项PDE占32bit(4B),因此“页目录表”中最多有4096B/4B=1024个PDE;1024个PDE对应1024个页表,而每个“页表”又占用一个物理内存块。综上,
“页目录表”占用内存 =4KB
“页表”占用内存 =1024*4KB =4MB
∴仅仅是“页目录表”和“页表”这种索引性质的东西(还不是真正要加载到内存的代码和数据)就占用了4MB+4KB
%include "pm.inc" ; 常量, 宏, 以及一些说明
PageDirBase equ 200000h ; 页目录开始地址: 2M
PageTblBase equ 201000h ; 页表开始地址: 2M + 4K
org 0100h
jmp LABEL_BEGIN
[SECTION .gdt]
; GDT
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描述符
LABEL_DESC_PAGE_DIR: Descriptor PageDirBase, 4096-1, DA_DRW ; Page Directory
LABEL_DESC_PAGE_TBL: Descriptor PageTblBase, 4096 * 8 - 1, DA_DRW ; Page Tables
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ; 非一致代码段, 32
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非一致代码段, 16
LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW ; Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA + DA_32 ; Stack, 32 位
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址
; GDT 结束
GdtLen equ $ - LABEL_GDT ; GDT长度
GdtPtr dw GdtLen - 1 ; GDT界限
dd 0 ; GDT基地址,等一会儿在.s16这个实模式段中将GDT的基地址放到[GdtPtr+2]开头的4个字节中的,现在先不着急,先用0初始化即可。
; 等一会儿会使用命令 lgdt [GdtPtr] 加载GdtPtr这6个字节到寄存器GDTR中
; GDT 选择子
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorPageDir equ LABEL_DESC_PAGE_DIR - LABEL_GDT
SelectorPageTbl equ LABEL_DESC_PAGE_TBL - LABEL_GDT
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
SelectorData equ LABEL_DESC_DATA - LABEL_GDT
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
; END of [SECTION .gdt]
[SECTION .data1] ; 数据段
ALIGN 32
[BITS 32]
LABEL_DATA:
; 实模式下使用这些符号 (i.e. _szPMMessage)
; 字符串
_szPMMessage: db "In Protect Mode now. ^-^", 0Ah, 0Ah, 0 ; 进入保护模式后显示此字符串
_szMemChkTitle: db "BaseAddrL BaseAddrH LengthLow LengthHigh Type", 0Ah, 0 ; 进入保护模式后显示此字符串
_szRAMSize db "RAM size:", 0
_szReturn db 0Ah, 0
; 变量
_wSPValueInRealMode dw 0
_dwMCRNumber: dd 0 ; Memory Check Result --> 放置ARDS结构数组的结构元素个数
_dwDispPos: dd (80 * 6 + 0) * 2 ; 屏幕第 6 行, 第 0 列。
_dwMemSize: dd 0
_ARDStruct: ; Address Range Descriptor Structure
_dwBaseAddrLow: dd 0
_dwBaseAddrHigh: dd 0
_dwLengthLow: dd 0
_dwLengthHigh: dd 0
_dwType: dd 0
_MemChkBuf: times 256 db 0
; 保护模式下使用这些符号(i.e. szPMMessage)
szPMMessage equ _szPMMessage - $$
szMemChkTitle equ _szMemChkTitle - $$
szRAMSize equ _szRAMSize - $$
szReturn equ _szReturn - $$
dwDispPos equ _dwDispPos - $$
dwMemSize equ _dwMemSize - $$
dwMCRNumber equ _dwMCRNumber - $$
ARDStruct equ _ARDStruct - $$
dwBaseAddrLow equ _dwBaseAddrLow - $$
dwBaseAddrHigh equ _dwBaseAddrHigh - $$
dwLengthLow equ _dwLengthLow - $$
dwLengthHigh equ _dwLengthHigh - $$
dwType equ _dwType - $$
MemChkBuf equ _MemChkBuf - $$
DataLen equ $ - LABEL_DATA
; END of [SECTION .data1]
; 全局堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
times 512 db 0
TopOfStack equ $ - LABEL_STACK - 1
; END of [SECTION .gs]
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0100h ;注:(软件)堆栈由程序人员在存储器中划出的一块存储区,向地址减小的方向堆积。
mov [LABEL_GO_BACK_TO_REAL+3], ax
mov [_wSPValueInRealMode], sp
; 得到内存数-------------------------------->代码1
mov ebx, 0
mov di, _MemChkBuf
.loop:
mov eax, 0E820h
mov ecx, 20
mov edx, 0534D4150h
int 15h ;调用这个中断,下一块内存的信息会被放入[es:di]
; BIOS中断 和 DOS中断:
; bios中断(int 1~20h)是主板预装好的BIOS提供的功能;dos中断(int 21H)则需要使用操作系统。调用方式都是int #. 例如,例如,
; INT 17H是打印机I/O调用的BIOS中断,(1)当AH=0时,把AL中的字符在打印机上打印出来;(2)当AH=1时,把AL中的初始化控制命令传送给打印机;(3)当AH=2时,把打印机的状态读至AL寄存器。这里17H是中断号,AH是功能号,AL是调用参数,(1)可以简记为“INT 17H/0”.
; 注:BIOS,实际上就是微机的基本输入输出系统(Basic Input-Output System),其内容集成在微机主板上的一个ROM芯片上,主要保存着有关微机系统最重要的基本输入输出程序,系统信息设置、开机上电自检程序和系统启动自举程序等。
; BIOS功能主要包括以下方面:一是BIOS中断服务程序,即微机系统中软件与硬件之间的一个可编程接口,主要用于程序软件功能与微机硬件之间实现衔接。操作系统对软盘、硬盘、光驱、键盘、显示器等外围设备的管理,都是直接建立在BIOS系统中断服务程序的基础上,操作人员也可以通过访问 INT 5、INT 13等中断点而直接调用BIOS中断服务程序。二是BIOS系统设置程序,前面谈到微机部件配置记录是放在一块可读写的CMOS RAM芯片中的,主要保存着系统基本情况、CPU特性、软硬盘驱动器、显示器、键盘等部件的信息。在BIOS ROM芯片中装有“系统设置程序”,主要用来设置CMOS RAM中的各项参数。这个程序在开机时按下某个特定键即可进入设置状态,并提供了良好的界面供操作人员使用。事实上,这个设置CMOS参数的过程,习惯上也称为“BIOS设置”。第三是POST上电自检程序,微机按通电源后,系统首先由POST(Power On Self Test,上电自检)程序来对内部各个设备进行检查。通常完整的POST自检将包括对CPU、640K基本内存、1M以上的扩展内存、ROM、主板、 CMOS存贮器、串并口、显示卡、软硬盘子系统及键盘进行测试,一旦在自检中发现问题,系统将给出提示信息或鸣笛警告。第四为BIOS系统启动自举程序,系统在完成POST自检后,ROM BIOS就首先按照系统CMOS设置中保存的启动顺序搜寻软硬盘驱动器及CD—ROM、网络服务器等有效地启动驱动器,读入操作系统引导记录,然后将系统控制权交给引导记录,并由引导记录来完成系统的顺利启动。
; 这么看来,int 15h是一个BIOS中断调用咯! 关于int 15h, 详见这里http://blog.csdn.net/gxfan/article/details/2962549
jc LABEL_MEM_CHK_FAIL ;若CF==0,则出错
add di, 20
inc dword [_dwMCRNumber]
cmp ebx, 0
jne .loop ;若CF==0, ebx==0,则还有下一块内存的信息
jmp LABEL_MEM_CHK_OK
LABEL_MEM_CHK_FAIL:
mov dword [_dwMCRNumber], 0
LABEL_MEM_CHK_OK:
; 初始化 16 位代码段描述符
;;;;;;;;;;;;将16位代码段段基址放到eax中;;;;;;;;;;;;
mov ax, cs
movzx eax, ax
shl eax, 4
add eax, LABEL_SEG_CODE16
;;;;;;;;;;;将段基址放到相应位置;;;;;;;;;;;
mov word [LABEL_DESC_CODE16 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE16 + 4], al
mov byte [LABEL_DESC_CODE16 + 7], ah
; 初始化 32 位代码段描述符
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32
mov word [LABEL_DESC_CODE32 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE32 + 4], al
mov byte [LABEL_DESC_CODE32 + 7], ah
; 初始化数据段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_DATA
mov word [LABEL_DESC_DATA + 2], ax
shr eax, 16
mov byte [LABEL_DESC_DATA + 4], al
mov byte [LABEL_DESC_DATA + 7], ah
; 初始化堆栈段描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_STACK
mov word [LABEL_DESC_STACK + 2], ax
shr eax, 16
mov byte [LABEL_DESC_STACK + 4], al
mov byte [LABEL_DESC_STACK + 7], ah
; 为加载 GDTR 作准备
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_GDT ; eax <- gdt 基地址
mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址
; 加载 GDTR
lgdt [GdtPtr]
; 关中断
cli
; 打开地址线A20 (将92端口一个字节的第1位置为1)
in al, 92h --> 从92端口读一个字节到al
or al, 00000010b
out 92h, al --> 将al持有的数据写到92端口
; 准备切换到保护模式
mov eax, cr0
or eax, 1
mov cr0, eax
; 真正进入保护模式
jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, [_wSPValueInRealMode]
in al, 92h ; ┓
and al, 11111101b ; ┣ 关闭 A20 地址线
out 92h, al ; ┛
sti ; 开中断
mov ax, 4c00h ; ┓
int 21h ; ┛回到 DOS
; 上面是一个DOS中断调用(不是BIOS中断调用), int 21h中的21h是中断号,AH=4ch是“功能号”,AL=00h是“中断调用参数”。这里的功能是“带返回码结束,AL=返回码”。
; END of [SECTION .s16]
[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS 32]
LABEL_SEG_CODE32:
mov ax, SelectorData
mov ds, ax ; 数据段选择子
mov ax, SelectorData
mov es, ax
mov ax, SelectorVideo
mov gs, ax ; 视频段选择子
mov ax, SelectorStack
mov ss, ax ; 堆栈段选择子
mov esp, TopOfStack
; 下面显示一个字符串,用法详见后面“保护模式下显示字符串”
push szPMMessage call DispStr add esp, 4
push szMemChkTitle
call DispStr
add esp, 4
call DispMemSize ; 显示内存信息
call SetupPaging ; 启动分页机制
; 到此停止
jmp SelectorCode16:0
; 启动分页机制 --------------------------------------------------------------
SetupPaging:
;1、计算出最大地址为[dwMemSize]对应的内存共有多少个页表(也即PDE个数,不是页面个数),将个数(ecx,32bit)压栈
xor edx, edx
mov eax, [dwMemSize] ;根据自己机器的实际内存大小来设置页目录表和页表
mov ebx, 400000h ; 400000h = 4M = 4096 * 1024, 一个页表对应的内存大小(一个页面是4k,一个页表有1024个页面)
div ebx ; edx:eax / ebx ==> eax ...... edx
mov ecx, eax ; 此时 ecx 为页表的个数,也即 PDE 应该的个数
test edx, edx
jz .no_remainder
inc ecx ; 如果余数不为 0 就需增加一个页表
.no_remainder:
push ecx ; 暂存页表个数
; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.
;2、首先初始化“页目录表”(即初始化每个PDE)
mov ax, SelectorPageDir ; 此段首地址为 PageDirBase
mov es, ax
xor edi, edi
xor eax, eax
mov eax, PageTblBase | PG_P | PG_USU | PG_RWW
.1:
stosd ; eax中的4个字节 -> es:edi ,每循环一次是一个PDE
add eax, 4096 ; 为了简化, 所有页表在内存中是连续的.
loop .1 ; 循环次数为ecx=PDE个数
;3、再初始化所有“页表”,即初始化每个PTE
mov ax, SelectorPageTbl ; 此段首地址为 PageTblBase
mov es, ax
pop eax ; 页表个数,也是PDE个数
mov ebx, 1024 ; 每个页表 1024 个 PTE
mul ebx ; eax*ebx==>积edx:eax
mov ecx, eax ; PTE个数 = 页表个数 * 1024
xor edi, edi
xor eax, eax
mov eax, PG_P | PG_USU | PG_RWW
.2:
stosd ; eax==>es:edi
add eax, 4096 ; 每一页指向 4K 的空间
loop .2 ; 循环次数为ecx=PTE个数
;4、开启页表机制
mov eax, PageDirBase
mov cr3, eax
mov eax, cr0
or eax, 80000000h
mov cr0, eax
jmp short .3
.3:
nop
ret
; 分页机制启动完毕 ----------------------------------------------------------
DispMemSize:
push esi
push edi
push ecx
mov esi, MemChkBuf
mov ecx, [dwMCRNumber];for(int i=0;i<[MCRNumber];i++)//每次得到一个ARDS
;注意到, ds:esi ==> MemChkBuf ,是一个线性结构; es:edi ==> ARDStruct,是二维数组
.loop: ;{
mov edx, 5 ; for(int j=0;j<5;j++) //每次得到一个ARDS中的成员
mov edi, ARDStruct ; {//依次显示BaseAddrLow,BaseAddrHigh,LengthLow,
.1: ; LengthHigh,Type
push dword [esi] ;
call DispInt ; DispInt(MemChkBuf[j*4]); //显示一个成员,一个成员有四个字节dword
pop eax ; db-> BYTE, dw->WORD, dd->DWORD
stosd ; ARDStruct[j*4] = MemChkBuf[j*4]; stosd指令:将eax的四个字节放到es:edi(ARDStruct)中
add esi, 4 ;
dec edx ;
cmp edx, 0 ;
jnz .1 ; }
call DispReturn ; printf("\n");
cmp dword [dwType], 1 ; if(Type == AddressRangeMemory) ; 通过上面stosd,已经填充好了dwType
jne .2 ; {
mov eax, [dwBaseAddrLow] ;
add eax, [dwLengthLow] ;
cmp eax, [dwMemSize] ; if(BaseAddrLow + LengthLow >= MemSize)
jb .2 ; jb==jump below
mov [dwMemSize], eax ;MemSize = BaseAddrLow + LengthLow; 等号右边是当前这个内存块最后一个字节的地址
.2: ; }
loop .loop ;}
;
call DispReturn ;printf("\n");
push szRAMSize ;
call DispStr ;printf("RAM size:");
add esp, 4 ;
;
push dword [dwMemSize] ;
call DispInt ;DispInt(MemSize);
add esp, 4 ;
pop ecx
pop edi
pop esi
ret
%include "lib.inc" ; 库函数
SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]
; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
[SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:
; 跳回实模式:
mov ax, SelectorNormal
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov eax, cr0
and eax, 7FFFFFFEh ; PE=0, PG=0
mov cr0, eax
LABEL_GO_BACK_TO_REAL:
jmp 0:LABEL_REAL_ENTRY ; 段地址会在程序开始处被设置成正确的值
Code16Len equ $ - LABEL_SEG_CODE16
; END of [SECTION .s16code]
**********************************************************************************************************************************
代码1执行结果如下图:
**********************************************************************************************************************************
程序效果示意图:
可以看到,我的电脑可以使用的内存确实能达到4G(FFFC0000 h + 00040000 h=1 0000 0000 h ==> 4GB),但可供OS使用的内存大小范围仅到32GB(type=1, 00100000 h+01EF0000 h = 1FF0000 h ==> 32MB).
二、初始化页目录表、页表、开启分页机制
知道哪些内存可以使用后,我们就可以节省地 构造自己的“页目录表”和“页表”,并开启分页机制了。代码在上面已经给出,即SetupPaging 这个函数。
三、一个细节——保护模式下显示字符串
这里讲“保护模式下实现字符串”主要是分析一下上面程序中调用到的一个函数DispStr,并无涉及对本节课程的理解。
DispStr调用方法:
[SECTION .data1] [BITS 32] ... _szPMMessage: db "In Protect Mode now. ^-^",0Ah,0Ah,0 ;保护模式显示 szPMMessage equ _szPMMessage - $$ ... push szPMMessage ;将要显示的字符串指针入栈 call DispStr add esp, 4 ;将显示了的字符串指针出栈
DispStr实现:
DispStr:
push ebp
mov ebp, esp ;-->此后,esp中放的是TopOfStack指针,指向栈顶
push ebx
push esi
push edi
mov esi, [ebp+8] ;取出在函数DispStr调用前被压栈的那个”字” szPMMessage
mov edi, [dwDispPos]
;初始时_dwDispPos: dd (80 * 6 + 0) * 2; 屏幕第6行, 第0列,是屏幕上下一个显示的位置
;dwDispPos equ _dwDispPos - $$
mov ah, 0Fh
.1:
lodsb ;lodsb-->将esi中的一个字节放到AL中
test al, al
jz .2 ;是结束字符0
cmp al, 0Ah;
jnz .3 ;是“非回车的字符”
;;;;;;;;;;;;;;;;是“回车”的时候;;;;;;;;;;;;;;;;
;1) 求得下一行的行数
push eax
mov eax, edi ;ax(=edi),为被除数(16bit)
mov bl, 160 ;bl,为除数(8bit)
div bl ;ah为余数,al为商
and eax, 0FFh ;将余数去掉,eax为商(即当前字符的“行数”)
inc eax ;eax为下一行的行数
;2) 将edi指向显存中下一行的第一个字符处
mov bl, 160 ;一行80个字符,一个字符对应显存中的2byte
mul bl ;bl寄存器中的值乘上al寄存器中的值,积在ax中
mov edi, eax
pop eax
jmp .1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.3: ;是“非回车的字符”
mov [gs:edi], ax
add edi, 2
jmp .1
.2: ;是结束字符0
mov [dwDispPos], edi
pop edi
pop esi
pop ebx
pop ebp
ret
注意:
1) mov esi, [ebp+8] 取出字符串指针szPMMessage
;
; |-----------------------|
; | edi | <== ebp
; |-----------------------|
; | esi | <== ebp+2
; |-----------------------|
; | ebx | <== ebp+4
; |-----------------------|
; | ebp | <== ebp+6
; |-----------------------|
; | szPMMessage | <== ebp+8
; |-----------------------|
; | *** |
; |-----------------------|
其中,edi,esi,ebx,ebp是在函数DispStr中压入的;szPMMessage是在调用这个函数之前压栈的,这个字符串就是要被显示的字符串
; | ... |
; |---------------|
; | 'I' | <==szPMMessage/esi均指向这个位置
; |---------------|
; | 'n' |
; |---------------|
; | ' ' |
; |---------------|
; | 'P' |
; |---------------|
; | 'r' |
; |---------------|
; | ... |
; |---------------|
相关推荐
Linux 内核分析与应用课件第 2 章(三)分页机制 Linux 内核分析与应用课件第 2 章(三)分页机制主要讲解了分页机制的原理和实现方法。分页机制是操作系统中虚拟存储器管理的重要组成部分,它将虚拟地址空间或线性...
在讨论王道操作系统思维导图第三章的内存管理时,我们将会触及操作系统中的核心概念之一——内存管理。内存管理是操作系统中负责管理计算机系统中主存储器资源的重要功能,它涉及如何有效地分配、使用和回收内存空间...
《深入理解Linux内核中文第三版》是一部针对Linux 2.6内核的权威指南,其第8章专门探讨了“内存管理”这一核心主题。内存管理是操作系统中至关重要的一环,它涉及到如何分配、使用和回收系统内存,以确保程序高效、...
操作系统第三章内存管理是计算机科学中的一门重要课程,涉及到计算机系统中内存管理的各种机制和算法。本章节将详细介绍内存管理的基本概念、内存分配方式、内存保护机制、虚拟内存技术等内容。 一、内存管理的基本...
操作系统第3章 物理和虚拟内存 操作系统中,内存管理是最重要的任务之一。物理内存是计算机系统的主要组件之一,负责存储程序和数据。物理内存的组织和管理方式对操作系统的设计产生了重大的影响。在本章中,我们将...
### 操作系统第三章内存管理习题详细解答 #### 第一题:内存管理概念与实现机制 本题探讨了在分时操作系统环境下内存管理的基本原理和技术。首先指出,在这种环境中,给不同用户分配的地址空间可能不相等,这一点...
《深入理解Linux内核》是Linux系统开发领域的经典著作,第三版中的第8章专门讲述了内存管理这一核心主题。在Linux操作系统中,内存管理对于系统的性能、稳定性和资源利用率至关重要。这一章的内容深入剖析了Linux...
- Linux内核并未完全采用Intel的段机制,而是主要依赖分页机制。所有段基地址为0,逻辑地址与线性地址相同,简化了设计并便于移植。 - Linux的虚拟内存机制通过地址映射、内存分配回收、缓存刷新等机制实现,但...
3. **内存分页**:内存被划分为固定大小的页,如4KB,便于管理和调度。页的大小会影响内存利用率和地址转换速度。 4. **内存管理单元MMU**:MMU(Memory Management Unit)负责地址转换和权限检查,确保进程只能...
《深入理解Linux内核》是Linux领域的经典之作,它的第三版更是深受读者喜爱。这份压缩包包含的是第8至11章的内容,分别是“内存管理”、“进程地址空间”、“系统调用”和“信号”。这四个章节涵盖了Linux内核中的...
Linux内核分析与应用课件第2章(一)内存管理之内存寻址 本节课程主要讲解了Linux内核分析与应用中的内存寻址机制。从图灵机的概念开始,讲解了计算机体系结构中的核心问题之一---内存寻址技术。内存寻址技术是...
在第三章,可能会讨论如何实现虚拟内存、分页或分段机制,以及如何防止内存泄漏和数据损坏。通过阅读源码,我们可以更好地掌握内存管理的实践技巧。 I/O系统管理设备交互,包括硬盘、网络接口、键盘和显示器等。这...
《深入理解Linux内核》是Linux系统开发领域的经典著作,第三版更是对现代Linux内核的深入剖析。其中,第8章聚焦于“内存管理”,这是操作系统核心功能之一,对于理解Linux系统的性能和稳定性至关重要。本章内容涵盖...
### 第 3 章 启动参数 Memcached的启动参数对SLAB机制的性能有直接影响: - `-m`:指定Memcached可以使用的最大内存,单位为MB。这是Memcached性能的关键参数,决定了它可以存储的数据量。 - `-M`:当内存耗尽时...
4. 存储器组织:讨论内存的分页和分段机制,这些是操作系统管理和保护内存空间的方式。 5. 内存管理:包括虚拟内存的概念,它是如何将物理内存和磁盘上的交换空间结合起来,使程序可以使用超过实际物理内存容量的...
这种模式通过使用段描述符表和分页机制来实现,确保了程序在执行时对内存的访问受到严格的控制。 首先,段描述符表是保护机制的基础,它存储了每个段的属性,如段的基地址、段的大小、访问权限等。每个进程或线程都...
虚拟内存是操作系统中一个至关重要的概念,它允许程序使用比实际物理内存更大的地址空间,通过将部分数据在需要时才加载到内存,从而解决了内存不足的问题。本复查测验主要考察了虚拟内存管理和页替换算法的相关知识...
第五章的内容主要涉及程序装入、链接、内存管理、动态重定位、分区分配算法、对换技术、分页和分段存储管理。 1. 程序装入内存的方式主要有三种:绝对装入、可重定位装入和动态运行时装入。绝对装入方式适用于单道...