0、开篇:
(1)存储程序方式指的是什么?
在存储装置中保存程序,并逐一运行的方式
(2)通过使用内存来提高磁盘访问速度的机制称为什么?
磁盘缓存
(3)把磁盘的一部分作为假想内存来使用的机制称为什么?
虚拟内存
(4)Windows中,在程序运行时,存储着可以动态加载调用的函数和数据的文件称为什么?
动态链接库
(5)在EXE程序文件中,静态加载函数的方式称为什么?
静态链接
(6)在Windows计算机中,一般磁盘的1个扇区是多少字节?
512字节
1、不读入内存就无法运行
程序保存在存储设备中,通过有序地被读出来实现运行,这一点大家都很清楚。这一机制称为存储程序方式(程序内置方式)。
然而,在磁盘中保存的原始程序是无法直接运行的,因为负责解析和运行程序内容的CPU,需要通过内部程序计数器来指定内存地址,然后才能读出程序。即使CPU可以直接读出并运行磁盘中保存的程序,由于磁盘读取速度慢,程序的运行速度还是会降低。总之,存储在磁盘中的程序需要读入到内存后才能运行。
2、磁盘缓存加快了磁盘访问速度
磁盘缓存指的是把从磁盘中读出的数据存储到内存空间中的方式。这样一来,当接下来需要读取同一数据时,就不用通过实际的磁盘,而是从磁盘缓存中把内容读出。使用磁盘缓存可以大大改善磁盘数据的访问速度。
3、虚拟内存把磁盘作为部分内存来使用
虚拟内存是指把磁盘的一部分作为假想的内存来使用。这与磁盘缓存是假想的磁盘(实际上是内存)相对,虚拟内存是假想的内存(实际上是磁盘)。
通过借助虚拟内存,在内存不足时也可以运行程序。例如,在只剩下5MB内存空间的情况下也能运行10MB大小的程序。不过,就如本章开头所讲述的那样,CPU只能执行加载到内存中的程序。虚拟内存虽说是把磁盘作为内存的一部分来使用,但实际上正在运行的程序部分,在这个时间点上是必须存在内存中的。也就是说,为了实现虚拟内存,就必须把实际内存(也称为物理内存)的内容,和磁盘上的虚拟内存的内容进行部分置换(swap),并同时运行程序。
虚拟内存的方式有分页式和分段式两种。Windows采用的是分页式。该方式是指,在不考虑程序构造的情况下,把运行的程序按照一定大小的页(Page)进行分割,并以页位单位在内存和磁盘间进行置换。在分页式中,我们把磁盘的内容读出到内存称为Page In,把内存的内容写入磁盘称为Page Out。一般情况下,Windows计算机的页的大小是4KB。也就是说,把大程序用4KB的页来进行切分,并以页为单位放入磁盘(虚拟内存)或内存中。
4、节约内存的编程方法
许多人可能会认为,通过借助磁盘虚拟内存就可以解决内存不足的问题。而虚拟内存也确实能避免因内存不足导致的应用无法启动。不过,由于使用虚拟内存时发生的Page In和Page Out往往伴随着低速的磁盘访问,因此在这个过程中,应用的运行会变得迟钝起来。总的来说,虚拟内存无法彻底解决内存不足的问题。
为了从根本上解决内存不足的问题,需要增加内存的容量,或者尽量把运行的应用文件变小。接下来会向大家介绍两个把应用文件变小的编程方法。
(1)通过DLL文件实现函数共有
DLL(动态链接库),顾名思义就是在程序运行时可以动态加载Library(函数和数据的集合)的文件。此外,还有一个需要大家注意的地方,那就是多个应用可以共有同一个DLL文件。而通过共有一个DLL文件则可以达到节约内存的效果。
例如我们编写了一个具有某些处理功能的函数MyFunc()。应用A和应用B都会使用这个函数,如果将这个函数内置(静态链接),同时运行这两个应用,内存中就存在了具有同一函数的两个程序。这会导致内存的利用率变低。
如果函数MyFunc()是独立的DLL文件而不是应用的执行文件(EXE文件)。由于同一个DLL文件的内容在运行时可以被多个应用共有,因此内存中存在的函数MyFunc()的程序就只有1个,这样一来,内存的利用效率就提高了。
Windows的操作系统本身也是多个DLL文件的集合体。DLL还有一个优点就是在不变更EXE文件的情况下,只通过升级DLL文件就可以更新。
(2)通过调用_stdcall来减小程序文件的大小
C语言中,在调用函数后,需要执行栈清理处理指令。栈清理处理是指,把不需要的数据从接收和传递函数的参数时使用的内存上的栈区域中清理出去。该命令不是程序记述的,而是在程序编译时由编译器自动附加到程序中的。编译器默认将该处理附加在函数调用方。
上面代码中,函数main()中调用了函数MyFunc()。按照默认设定,栈的清理处理会附加在函数main()这一方。在同一个程序中,同样的函数可能会被多次反复调用。而如果是同样的函数,栈清理处理的内容也是一样的。由于该处理是在调用函数的一方,因此就会导致同一处理被反复调用。这就造成了内存的浪费。
在下图的汇编语言:
在32位CPU中,1次push指令可以存储4个字节的数据。在上面的代码清单中,由于使用了两次push指令把两个参数(456和123)存入到了栈中,因此总的来说就是存储了8字节的数据。通过call指令调用函数MyFunc()后,栈中存储的数据就不再需要了。于是这时就通过add esp 8这个指令,是存储着栈数据的esp寄存器前进8位来进行数据清理。
栈清理处理,比起在函数调用方进行,在反复被调用的函数一方进行时,程序整体要小一些。这时所使用的就是_stdcall。在函数前加上_stdcall,就可以把栈清理处理变为在被调用函数一方进行。
5、磁盘的物理结构
磁盘的物理结构是指磁盘存储数据的形式。
磁盘是通过把其物理表面划分成多个空间来使用的。划分的方式有扇区方式和可变长方式两种,前者是指将磁盘划分为固定长度的空间,后者则是指把磁盘划分为长度可变的空间。一般Windows计算机所使用的硬盘和软盘,采用的都是扇区方式。扇区方式中,把磁盘表面分成若干个同心圆的空间就是磁道,把磁道按照固定大小(能存储的数据长度相同)划分而成的空间就是扇区。
扇区是对磁盘进行物理读写的最小单位。Windows中使用的磁盘,一般1个扇区是512字节。不过,Windows在逻辑方面(软件方面)对磁盘进行读写的单位是扇区整数倍簇。根据磁盘容量的不同,1簇可以是512字节(1簇=1扇区),1KB(1簇=2扇区),2KB,4KB,8KB,16KB,32KB(1簇=64扇区)。磁盘的容量越大,簇的容量也越大。
这是我计算机上C盘的情况 采用的是4KB。不管是硬盘还是软盘,不同的文件是不能存储在同一个簇中的,否则就会导致只有一方的文件不能被删除。因此,不管多么小的文件,都会占用1簇的空间。所以说,所有的文件都会占用1簇的整数倍的磁盘空间。
以簇位单位进行读写时,1簇中没有填满的区域会保持不被使用的状态。虽然这看起来有点浪费,不过该机制就是如此规定的,所以我们也没有什么好办法。另外,如果减少簇的容量,磁盘访问次数就会增加,就会导致读写文件的时间变长。由于在磁盘表面上,表示扇区区分的领域是必要的,因此,如果簇的容量过小,磁盘的整体容量也会减少。扇区和簇的大小,是由处理速度和存储容量的平衡来决定的。