内存和磁盘的关系解读(读书笔记)

tech2025-06-03  13

内存和磁盘的关系解读

不读入内存就无法运行

  在考虑内存和磁盘之间的关系之前,我们首先来看一个前提性的东西。   程序保存在存储设备中,通过有序的被读出来实现运行,这一点搭建都很清楚。在一机制被称为存储程序方式(程序内置方式),现在看来是理所当然的,但在当时他的提出可以说是一个里程碑式。因为在此之前的程序都是通过改变计算机的布线等改变程序的。   计算机中主要的存储部件是内存和磁盘。磁盘中存储程序,必须要加载到内存后才能运行。在磁盘中保存的原始程序是无法运行的,这是因为负责解析和运行内容的CPU需要通过内部程序计数器来指定内存地址,然后才能读出程序,即使CPU可以直接运行读出并运行磁盘中保存的程序,由于磁盘读取速度慢,程序的运行速度还是会降低。总之,存储在磁庞中的程序需要读入到内存中才能运行。在考虑内存和磁盘的关系之前,大家一定要了解这个前提。

磁盘缓存加快了磁盘的访问速度

  作为体现内存和磁盘亲密关系的第一个示例,首先让我们来看一下磁盘缓存(disk cache)。磁盘缓存指的是把从磁盘读取的数据存储到内存汇空间中的方式,这样一来,当接下来需要读取同一数据时,就不用通过实际的磁盘,而是从磁盘缓存中把内容读取出来,使用磁盘缓存可以大大提升磁盘数据的访问速度。   Windows提供了磁盘缓存机制作为操作系统。不过对普通用户来说,磁盘缓存发挥显著效果的时代只延续到Windows 95/98.现在,随着硬盘访问速度的大幅提升,磁盘缓存的效果也没有之前那么明显了。   把低速设备的数据保存在高速设备中,需要时可以直接将其从高速设备中读取出,这样缓存的方式在其他情况下也还会用到。其中的一个实例就是在web浏览器中的使用。由于web浏览器是通过网络来获取远程web服务器的数据并将其显示出来。因此,在显示较大的图片等文件时,会花费不少时间。于是web浏览器就可以把获取的数据暂时保存在磁盘中,然后再需要的时再从显示磁盘中的数据。也就是说把低速的网络数据保存到相对高速的磁盘中。

虚拟内存把磁盘作为部分内存使用

  虚拟内存是指把磁盘的一部分作为假想的内存来使用。这与磁盘缓存是假想的磁盘(实际上是内存)是相对的,虚拟内存是假想的内存(实际上是磁盘)。   通过借助虚拟内存,在内存不足时也可以运行程序。例如,在只剩下5mb的内存空间的情况下也能运行10mb大小的程序。不过,CPU只能执行加载到内存中的程序,虚拟内存虽说是把磁盘作为内存的一部分来使用,但实际上正在运行的程序部分,在这个时间点上是必须存在在内存中的,也就是说,为了实现虚拟内存,就必须把实际内存(也称物理内存)和磁盘上的虚拟内存的内容进行部分置换,并同时运行程序。

  刚才已经说了,Windows提供了虚拟内存机制作为操作系统的。在当前的Windows中,虚拟内存的方法有分页式和分段式两种。

分段式虚拟内存是指,把要运行的程序分割成以处理集合即数据集合等为单位的段落,然后再以分割后的段落为单位在内存和磁盘之间进行数据置换。

  Windows采用的是分页式。该方式是指在不考虑程序构造的情况下,把运行的程序按照一定大小的页(page)进行分割,并以页为单位在内存和磁盘之间进行置换。在分页式中,我们把磁盘的内容读取到内存称为page In,把内存的内容写入磁盘称为page Out。一般情况下,Windows计算机的页的大小是4KB,也就是说把程序用4KB的也进行切分,并以页为单位放入磁盘(虚拟内存)或内存中。   为了实现虚拟内存功能,Windows在磁盘上提供了虚拟内存用的文件(pagefile,页文件)。改文件有Windows自动做成和管理。文件的大小也就是虚拟内存的大小,通常是实际内存的相同程度至两倍程度。通过Windows的控制面板,可以查找或变更当前虚拟内存的设置,具体实现可自行百度。

节约内存的方法

  以图形用户界面(GUI)为基础的Windows,可以说是一个巨大的操作系统。Windows的前身是MS-DOS操作系统,最初的版本可以在128KB左右的内存上运行,而想要Windows流程运行的话,至少需要512mb的内存。而且由于Windows具有多任务的功能,在巨大的Windows操作系统中可以同时运行多个应用,因此即使是512MB的内存,也无法保证流畅运行。 许多人可能会认为通过借助虚拟磁盘内存就可以解决内存不足的问题。而虚拟内存确实能避免内存不足导致应用无法启动。不过由于使用虚拟内存时发生的page In和page Out往往伴随着低速的磁盘访问,因此在这个过程中应用的运行会变得迟钝起来。导致应用一时无法操作的不愉快经历。也就是说虚拟内存无法彻底解决内存不足的问题。   为了从根本上解决内存不足的问题,需要增加内存的容量,或者尽量把运行的引用文件变小。接下来向大家介绍把应用文件变小的编程方法。虽然增加内存容量的更为方便,但是花费也高,所以大家先看看自己口袋里的银子在做决定。

通过DLL文件实现函数共有   DLL(Dynamic Link Library)文件,是在程序运行时可以动态加载Library(函数和数据的集合)的文件。此外,还有一个需要大家注意的地方,那就是多个应用可以共用同一个DLL文件。而通过共有同一个DLL文件则可以达到节约内存成本的效果。   假如,假设我们编写了一个具有某些处理功能的函数MyFunc()。应用A和应用B都会使用这个函数。在各个应用的运行文件中内置函数MyFunc()(这个称为Static Link,静态链接)后同时运行这两个应用,内存中就存在了具有同一函数的两个程序。但这会导致内存的利用率降低。所以,有两个同样的函数,还是有点浪费。   如果函数MyFunc()是独立的DLL文件而不是应用的执行文件(EXE文件),那结果又会怎样?由于同一DLL文件的内容在运行时可以被多个应用共有,因此内存中存在的函数MyFunc()的程序就只有一个,内存的效率也就提高了。   Windows的操作系统本省也是多个DLL文件的集合体。有时在安装新功能时,DLL文件也会被追加。应用则会通过利用这些DLl文件的功能来运行。从而达到节约空间的效果。而且DLL文件在不变更EXE文件的情况下,只通过升级DLL文件就可以更新。通过_stdcall来减少程序文件的大小   通过调用_stdcall来减少程序文件的方法,是用C语言编写应用时可以利用的高级技巧。C语言中,在调用函数后,需要执行栈清理的处理指令。栈清理处理指把不需要的数据从接受和传递函数的参数时使用的内存上的栈区域中清理出去。该命令不是程序记述的,而是在程序编译时由编译器自动的附加到程序中的。编译器的默认将该处理附加在函数调用方。   例如在如下代码中,从main函数中调用了MyFunc()。按照默认设定,栈的清理处理会附加在函数main()一方,在同一个程序中,同样的函数可能会被多次反复调用。而如果是同样的函数,栈清理处理的内容就会是一样的。由于该处理是在调用函数一方,因此就会导致同一处理被反复进行。造成内存的浪费。 //函数调用方 int main() { int a; a = Myfunc(123, 456); return 0; } //被调用方 int MyFunc(int a , int b) { ... }

虽然通过调用编译器的生成的机器语言执行文件就可以得知栈清理的处理内容,不过鉴于原始的机器语言不太好理解,所以我们用汇编语言的代码清单将其显示出来:   C语言通过栈来传递函数的参数。push是往栈中存入数据的指令。32位的CPU中,1次push指令可以存储4个字节的数据。上述代码中使用了两次push指令把参数存入到栈中,因此总的来说是存储了8个字节的数据。通过call指令调用函数MyFunc()后,栈中存储的数据就不在需要了。于是这时就通过add esp, 8指令,使存储着栈数据的esp寄存器前8位来进行数据清理。由于占是在各种情况下都可以再利用的内存领域,因此使用完毕后有必要将其恢复到原始状态。

磁盘的物理结构

  磁盘是通过把其物理表面划分成多个空间来使用的。划分的方式有扇形方式和可变长方式,前者是指将磁盘化分为固定长度的空间,后者则是指把磁盘划分为长度可变的空间。一般Windows计算机所使用的硬盘和软盘,采用的都是扇形方式。在扇区方式中,把磁盘表面分成若干个同心圆的空间就是磁道,把磁道按照固定的大小划分而成的空间就是扇区。   扇区是对磁盘进行物理读写的最小单位。Windows中使用的磁盘一般一个扇区是512字节。不过Windows在逻辑方面对磁盘进行读写的单位是扇区整数倍簇。根据磁盘容量的不同,1簇可以是512字节(1簇=1扇区),1KB(1簇=2扇区),2KB,4KB…磁盘的容量越大,簇的容量也就越大。不过在软盘中,1簇=512字节=1扇区,簇和扇区的大小是相等的。   不管是硬盘还是软盘,不同文件是不能存储在同一簇中的,否则就会导致只有一方的文件不能被删除。因此,不管是多么小的文件,都会占用簇空间,这样一来,所有的文件都会占用1簇的整数倍的磁盘空间。

最新回复(0)