物理内存和虚拟内存

一、物理内存

物理内存是计算机硬件中的重要组成部分,它也被称为RAM(随机访问存储器),是计算机用来存储和临时处理数据的地方。

定义:
物理内存是计算机中的一种硬件组件,用于存储数据和程序,以供中央处理单元(CPU)进行访问和处理。它是一种易失性存储器,这意味着当计算机断电或重新启动时,内存中的数据会丢失。

作用:
物理内存用于存储正在运行的操作系统、应用程序和数据。CPU可以快速地从物理内存中读取和写入数据,而不必像从硬盘或固态硬盘那样等待较长的访问时间。

存储单元:
物理内存通常以字节(bytes)为单位进行存储。每个字节都有唯一的物理地址,通过这些地址,CPU可以访问内存中的特定数据。

容量:
物理内存的容量通常以吉字节(GB)或兆字节(MB)来衡量。不同计算机和服务器具有不同大小的物理内存,可以根据需要进行扩展。

随机访问性质:
物理内存之所以称为RAM(随机访问存储器)是因为CPU可以随机访问内存中的任何位置,而不必按顺序读取数据。这种随机访问性质使内存非常适合快速读写数据,特别是在运行程序时。

寻址:
物理内存中的每个字节都有一个唯一的地址,通过地址总线和数据总线,CPU可以将特定地址中的数据读取到寄存器中进行处理。

虚拟内存:
虚拟内存是一种通过将数据从物理内存复制到硬盘上的虚拟存储空间来扩展物理内存的技术。这使得操作系统可以更有效地管理内存资源,以便在需要时将数据换入物理内存。

内存层次结构:
计算机系统通常拥有多个层次的内存,包括寄存器、高速缓存、物理内存和辅助存储设备(如硬盘或固态硬盘)。这些层次的内存在速度和容量方面有所不同,被用于不同类型的数据存储和访问。

综上,物理内存是计算机系统中的关键组件,它提供了一个快速且易于访问的存储空间,用于存储操作系统、应用程序和数据,以支持计算机的正常运行。它是计算机性能的重要因素之一,内存大小和性能对计算机的整体运行速度和多任务处理能力有重要影响。

二、虚拟内存

虚拟内存是计算机操作系统的一个关键概念,它允许程序访问比物理内存(RAM)更大的地址空间。虚拟内存是一种在物理内存和辅助存储设备(通常是硬盘或固态硬盘)之间的抽象内存层,它有助于提高系统的稳定性、多任务处理能力和程序的运行效率。

定义:
虚拟内存是计算机操作系统提供的一种机制,它允许程序访问一个伪装成物理内存的地址空间,而实际上,部分数据可能存储在辅助存储设备上。虚拟内存的目标是扩展可用内存,以便运行更大的程序或多个程序,同时提供了一种内存管理方式,使得程序不必关心物理内存的细节。

地址空间:
每个程序在虚拟内存中都有一个自己的地址空间,这个地址空间通常是连续的,从零开始。程序可以将数据写入自己的虚拟内存地址,但实际的数据可能存储在物理内存或磁盘上。

分页:
虚拟内存通常使用分页技术来管理数据。物理内存和磁盘都被划分成固定大小的页面(通常是4KB或更大),操作系统负责将数据从物理内存复制到磁盘(称为页面交换)或从磁盘加载到物理内存。这个过程是透明的,对于程序来说是不可见的。

地址翻译:
当程序尝试访问虚拟内存中的某个地址时,操作系统的内存管理单元(MMU)将虚拟地址转换成物理地址。这个地址翻译过程允许操作系统在物理内存和磁盘之间进行数据的动态调度和管理。

多任务处理:
虚拟内存使得多任务处理更加高效。每个运行的程序都有自己的虚拟地址空间,它可以认为自己独占整个内存。操作系统负责合理地分配物理内存和磁盘空间,以便同时运行多个程序,而不会干扰彼此。

内存交换:
当物理内存不足时,操作系统会根据需要将不常用的页面从物理内存换出到磁盘,以便为新的数据和程序腾出空间。这个过程被称为页面交换,它使得系统可以运行比物理内存更大的程序。

稳定性:
虚拟内存提高了系统的稳定性。即使程序出现错误或者内存泄漏,虚拟内存可以将问题限定在程序的虚拟地址空间内,而不会影响整个系统。

综上,虚拟内存是一种操作系统的关键特性,它允许程序访问比物理内存更大的地址空间,并提供了一种灵活的内存管理机制,以提高系统的性能、稳定性和多任务处理能力。虚拟内存的使用使得计算机可以运行更大、更复杂的程序,同时提供了更好的用户体验。

三、虚拟内存和物理内存的区别

虚拟内存和物理内存是计算机内存管理中两个重要的概念,它们在计算机内存管理中扮演不同的角色。虚拟内存允许系统在物理内存不足时继续运行程序,提高了系统的稳定性和多任务处理能力。然而,虚拟内存的访问速度相对较慢,因此物理内存仍然是对于性能关键任务的首选。操作系统负责管理这两种内存,以优化计算机的整体性能。现在对它们进行一些对比和区别:

定义:
物理内存:也称为RAM(随机访问存储器),是计算机的实际硬件内存,用于存储正在运行的程序和数据。它是计算机中的主要内存组件,是CPU直接访问的地方。
虚拟内存:是一种抽象的内存层,通过将数据存储在物理内存和辅助存储设备(通常是硬盘或固态硬盘)之间,扩展了可用内存。它为程序提供了一个假象,好像它们拥有比物理内存更大的地址空间。

容量:
物理内存的容量是硬件限制的,通常以吉字节(GB)或兆字节(MB)为单位。
虚拟内存的容量可以比物理内存大得多,它受到硬盘或固态硬盘的大小限制。

稳定性:
物理内存是易失性存储器,断电或重新启动计算机时,内存中的数据会丢失。
虚拟内存可以持久保存数据,因为它的一部分数据存储在辅助存储设备上,不受电源状态的影响。

速度:
物理内存的访问速度远远快于虚拟内存,因为它位于CPU芯片附近。
虚拟内存的访问速度通常较慢,因为它需要将数据从磁盘加载到物理内存中。

地址空间:
物理内存的地址空间是实际存在的,是硬件物理内存的一部分。
虚拟内存的地址空间是虚拟的,它提供了一个假象,好像程序拥有一个更大的内存地址空间。

管理:
物理内存的管理通常由操作系统和硬件控制,用于分配、回收和保护内存区域。
虚拟内存的管理也由操作系统控制,包括页面交换、地址映射和数据的动态加载和卸载。

多任务处理:
物理内存支持多任务处理,但受到物理内存容量的限制。
虚拟内存扩展了多任务处理的潜力,因为它允许操作系统将多个程序的数据存储在辅助存储设备上,只加载正在运行的程序的部分数据到物理内存。

效率:
物理内存访问速度更快,但容量有限。
虚拟内存提供了更大的容量,但访问速度相对较慢。

四、linux内核里的物理内存和虚拟内存

Linux内核中有多种方式可以用于在内核模块或驱动程序中申请物理内存和虚拟内存。在内核开发中,内存的管理和分配通常较为复杂,需要根据具体的驱动程序或内核模块的需求来选择适当的方式和函数。此外,内核内存分配可能会受到一些约束和安全性考虑,因此需要小心操作。如下是物理内存和虚拟内存的一些相关函数。

1、kmalloc() 和 kfree() 函数:
void* kmalloc(size_t size, gfp_t flags) 函数用于在内核中分配一块指定大小的物理内存。gfp_t 参数是用于设置内存分配的标志,例如,GFP_KERNEL 表示在内核上下文中分配内存。
void kfree(void* ptr) 函数用于释放先前由 kmalloc() 分配的内存。
示例代码:

#include <linux/slab.h>
void* ptr = kmalloc(1024, GFP_KERNEL); // 分配 1024 字节的内核内存
kfree(ptr); // 释放内存

2、vmalloc() 和 vfree() 函数:
void* vmalloc(unsigned long size) 函数用于在内核中分配大块虚拟内存,通常用于申请大量物理内存,因为物理内存可能不够大。
void vfree(void* addr) 函数用于释放由 vmalloc() 分配的虚拟内存。
示例代码:

#include <linux/vmalloc.h>
void* ptr = vmalloc(4096 * 1024); // 分配 4MB 的虚拟内存
vfree(ptr); // 释放虚拟内存

3、get_free_pages() 和 free_pages() 函数:
unsigned long get_free_pages(gfp_t flags, unsigned int order) 函数用于分配一页或多页的物理内存,并返回页框的地址。
void free_pages(unsigned long addr, unsigned int order) 函数用于释放先前由 get_free_pages() 分配的内存。
示例代码:

#include <linux/gfp.h>
unsigned long page = get_free_pages(GFP_KERNEL, 1); // 分配一页物理内存
free_pages(page, 1); // 释放内存

4、ioremap() 和 iounmap() 函数:
void* ioremap(resource_size_t offset, unsigned long size) 函数用于在内核中映射I/O内存地址,以便进行I/O操作。
void iounmap(void* addr) 函数用于解除I/O内存的映射。
示例代码:

#include <linux/ioport.h>
void* mapped_addr = ioremap(0x1000, 4096); // 映射I/O内存
iounmap(mapped_addr); // 解除映射

五、linux内核里相关内存申请函数的大致原理

1、kmalloc和kfree
kmalloc() 和 kfree() 函数是Linux内核中用于动态内存管理的核心函数。它们通过内存池来分配和释放内存,以提高内存分配的效率。这些函数的原理和实现在内核中得到了高度优化,以满足不同场景下的内存需求,并尽量减少内存碎片和浪费。

(1)kmalloc() 函数原理:
内存池初始化:
在Linux内核启动时,内存池(memory pool)会被初始化。这个内存池由一组物理内存块组成,通常是页面大小的倍数。这些物理内存块被划分成不同的大小类别,以便适应不同大小的内存分配请求。

内存分配请求:
当内核代码中的某个部分需要分配一块内存时,它会调用 kmalloc(size_t size, gfp_t flags) 函数。其中,size 参数表示要分配的内存大小,而 gfp_t 参数用于设置内存分配的标志,例如,GFP_KERNEL 表示在内核上下文中分配内存。

内存分配:
kmalloc() 函数会根据请求的内存大小和标志,在内存池中查找合适大小的内存块。如果找到合适大小的内存块,它会将该块标记为已分配,并返回该块的起始地址。如果没有足够的内存块可用,函数可能会尝试合并空闲块或者从内存中分配更多页面。

返回内存块地址:
kmalloc() 函数返回一个指向已分配内存块的指针,该指针可以用于在内核代码中访问分配的内存。

(2)kfree() 函数原理:
内存释放请求:
当内核代码中的某个部分不再需要一个先前通过 kmalloc() 分配的内存块时,它会调用 kfree(void* ptr) 函数,其中 ptr 是指向要释放的内存块的指针。

内存释放:
kfree() 函数会接收到一个指针,它会查找该指针对应的内存块,并将该内存块标记为空闲。这意味着内存块现在可供后续的 kmalloc() 调用使用。

合并和回收:
在一些情况下,kfree() 可能会执行内存块的合并操作,将相邻的空闲内存块合并成一个更大的内存块,以便更好地利用内存池。此外,如果内存块长时间未被使用,Linux内核可能会将它们返回给操作系统,以便其他应用程序或内核模块使用。

2、vmalloc和vfree
vmalloc() 和 vfree() 函数是Linux内核中用于管理虚拟内存的关键函数。它们允许内核代码分配和释放大块的虚拟内存,通过虚拟页表来建立虚拟内存和物理内存之间的映射关系。这使得内核可以高效地管理虚拟内存,以满足不同场景下的内存需求。这些函数的实现在内核中得到了高度优化,以提高内存分配和释放的性能和效率。

(1)vmalloc() 函数原理:
虚拟地址空间分配:
当内核代码中的某个部分需要分配大块虚拟内存时,它会调用 vmalloc(unsigned long size) 函数,其中 size 参数表示要分配的虚拟内存的大小。vmalloc() 函数在内核的虚拟地址空间中寻找足够大的、未使用的连续地址范围。

虚拟页表映射:
一旦找到足够的虚拟地址空间,vmalloc() 函数会建立虚拟内存和物理内存之间的映射。它使用虚拟页表来管理这些映射,将虚拟内存地址映射到物理内存地址。这允许内核代码使用虚拟内存地址来访问分配的内存。

返回虚拟内存地址:
vmalloc() 函数返回一个指向分配虚拟内存的指针,这个指针可以用于在内核代码中访问分配的虚拟内存。

(2)vfree() 函数原理:
虚拟内存释放请求:
当内核代码不再需要一个通过 vmalloc() 分配的虚拟内存块时,它会调用 vfree(void* addr) 函数,其中 addr 参数是指向要释放的虚拟内存的指针。

虚拟页表解除映射:
vfree() 函数接收到虚拟内存的地址,然后将该虚拟内存的页表项解除映射。这样,虚拟内存不再映射到物理内存,释放了虚拟地址空间。

内存回收:
一旦虚拟内存被释放,它变得可用于将来的 vmalloc() 调用。此外,如果虚拟内存长时间未被使用,Linux内核可能会将它返回给操作系统,以便其他应用程序或内核模块使用。

3、get_free_pages和 free_pages
get_free_pages() 和 free_pages() 函数是Linux内核中用于分配和释放多个物理页面的关键函数。它们通过管理内核的内存池来分配和释放物理页面,以满足不同场景下的内存需求。这些函数的实现在内核中得到了高度优化,以提高内存分配和释放的性能和效率。

(1)get_free_pages() 函数原理:
内存池初始化:
在Linux内核启动时,内存池(memory pool)会被初始化。这个内存池包含了系统中的所有物理内存页。通常,内核会将物理内存划分成不同的区域,以便更有效地管理内存分配。内存池中的每个页面都有一个状态,用于表示是否已经分配。

内存分配请求:
当内核代码需要分配多个物理页面时,它会调用 get_free_pages(gfp_t flags, unsigned int order) 函数。gfp_t 参数用于设置内存分配的标志,例如,GFP_KERNEL 表示在内核上下文中分配内存,而 order 参数表示要分配的页面数量,通常是2的幂次方。

页面分配:
get_free_pages() 函数会在内存池中查找连续的、空闲的物理页面块。这些页面块的数量由 order 参数指定。如果找到足够数量的页面块,函数会将它们标记为已分配,并返回它们的起始物理地址。

返回物理地址:
get_free_pages() 函数返回一个指向已分配物理页面块的物理地址。这个地址可以用于在内核代码中访问分配的物理内存。

(2)free_pages() 函数原理:
内存释放请求:
当内核代码不再需要通过 get_free_pages() 分配的物理页面块时,它会调用 free_pages(unsigned long addr, unsigned int order) 函数,其中 addr 参数是指向要释放的物理页面块的起始物理地址,而 order 参数是与分配时使用的 order 参数相同,用于指示要释放的页面数量。

页面释放:
free_pages() 函数会接收到一个物理地址和数量的请求,并将相应的页面块标记为空闲。这使得这些页面块可以被后续的 get_free_pages() 调用重新分配。

合并和回收:
在一些情况下,free_pages() 可能会执行物理页面块的合并操作,将相邻的空闲页面块合并成一个更大的页面块,以便更好地利用内存池。此外,如果页面块长时间未被使用,Linux内核可能会将它们返回给操作系统,以便其他应用程序或内核模块使用。

4、get_free_pages和 free_pages
ioremap() 和 iounmap() 函数是Linux内核中用于管理I/O内存映射的重要函数。它们允许内核代码与设备的I/O内存进行交互,同时确保内核地址空间和设备寄存器之间的正确映射关系。这些函数的原理和实现在内核中得到了高度优化,以提高I/O操作的性能和稳定性。

(1)ioremap() 函数原理:
映射请求:
当内核代码需要与设备寄存器进行交互,或者需要访问与设备相关的内存映射寄存器时,它会调用 ioremap(resource_size_t offset, unsigned long size) 函数。其中,offset 参数表示要映射的I/O内存地址的偏移量,而 size 参数表示要映射的地址范围的大小。

地址映射:
ioremap() 函数会为指定的地址范围分配一段内核虚拟地址空间,并将这个虚拟地址空间与设备的物理地址空间建立映射关系。这意味着通过虚拟地址可以访问设备的物理地址。

返回虚拟地址:
ioremap() 函数返回一个指向映射后的虚拟地址的指针,这个虚拟地址可以用于在内核代码中访问设备的I/O内存。

(2)iounmap() 函数原理:
解除映射请求:
当内核不再需要与设备的I/O内存映射进行交互时,或者在模块卸载时,它会调用 iounmap(void* addr) 函数,其中 addr 参数是通过 ioremap() 返回的虚拟地址。

映射解除:
iounmap() 函数接收到虚拟地址后,会解除这个虚拟地址与设备物理地址的映射关系。这使得虚拟地址不再能够访问设备的I/O内存。

资源释放:
除了解除映射,iounmap() 函数还会释放用于这个I/O内存映射的内核虚拟地址空间,以便将其用于其他用途。

5、kmalloc和vmalloc的区别
kmalloc() 和 vmalloc() 是Linux内核中用于分配内存的两个不同函数,它们适用于不同的用途,并有一些关键的区别。选择使用 kmalloc() 还是 vmalloc() 取决于你的内存需求。如果需要分配小块内存或需要直接与硬件设备交互,通常会选择 kmalloc()。而如果需要大块的内存,而物理内存又不足够大或不连续,那么 vmalloc() 是更合适的选择。

(1)内存类型:
kmalloc() 分配物理内存:kmalloc() 函数分配的内存是物理内存,这意味着它在物理RAM中存在。这种分配方式通常用于需要直接访问硬件设备或需要分配小块内存的情况。
vmalloc() 分配虚拟内存:vmalloc() 函数分配的内存是虚拟内存,它可能不直接对应物理内存。这种分配方式通常用于需要大块连续内存的情况,因为物理内存可能不足以满足这些需求。

(2)分配大小:
kmalloc() 适用于相对较小的内存分配:kmalloc() 主要用于分配小块内存,通常用于几百字节到几千字节的范围。
vmalloc() 适用于较大的内存分配:vmalloc() 适用于需要分配大量内存的情况,通常用于分配大于几千字节的内存块,甚至可以分配多兆字节的内存。

(3)内存分布:
kmalloc() 分配的内存通常位于内核的高端内存区域,这些内存块在物理地址上是连续的。这使得 kmalloc() 分配的内存非常适合直接与硬件设备交互。
vmalloc() 分配的内存则通常位于虚拟地址空间中,并且不一定连续。因此,它适用于需要大量内存但不需要物理连续性的情况。

(4)分配效率:
kmalloc() 在分配和释放小块内存时通常更高效,因为它不需要复杂的虚拟内存管理和分页机制。
vmalloc() 在分配大块内存时可能会引入一些额外的开销,因为它需要更复杂的虚拟内存管理和分页机制来处理大内存块的映射和分页表项。

6、kfree和vfree的区别
kfree() 和 vfree() 是Linux内核中用于释放内存的函数,它们适用于不同类型的内存分配。主要区别在于 kfree() 用于释放物理内存,而 vfree() 用于释放虚拟内存。选择哪个函数取决于你之前是如何分配内存的。如果是使用 kmalloc()分配的内存,应使用 kfree() 进行释放;如果是使用 vmalloc() 分配的内存,应使用 vfree() 进行释放。

(1)kfree() 函数:
适用于: kfree() 用于释放由 kmalloc() 函数分配的内存,这函数通常用于分配小块或一页的物理内存。

释放的内存类型: kfree() 释放的是物理内存,也就是真实的硬件RAM。这意味着通过 kfree() 释放的内存会立即回归到系统的可用物理内存池中。

参数: kfree() 接收一个指向要释放内存块的指针作为参数。

内存管理: kfree() 主要用于管理物理内存的分配和释放,它不涉及虚拟内存的映射或管理。

(2)vfree() 函数:
适用于: vfree() 用于释放由 vmalloc() 函数分配的内存,这些内存通常用于大块的虚拟内存分配。

释放的内存类型: vfree() 释放的是虚拟内存,这种内存通常不直接映射到物理RAM。虚拟内存可能会通过分页机制与物理内存交互,但它在虚拟地址空间中占据一定的位置。

参数: vfree() 接收一个指向要释放虚拟内存的指针作为参数。

内存管理: vfree() 主要用于管理虚拟内存的分配和释放,它涉及到虚拟地址空间的管理,包括映射和分页表项的更新。

7、vmalloc和vfree涉及的内存通常不直接映射到物理RAM的原因
vfree() 释放的虚拟内存通常不直接映射到物理RAM,是因为它们是通过虚拟内存管理机制进行管理的,而不是直接映射到物理RAM地址上。这涉及到虚拟内存系统的工作原理和内核内存管理的复杂性。

(1)虚拟内存映射: 在典型的操作系统中,包括Linux,虚拟内存被用于将进程的地址空间抽象成一系列虚拟页面。这些虚拟页面可以映射到物理RAM,也可以映射到磁盘上的交换空间。虚拟内存系统负责管理这些映射。

(2)分页系统: 虚拟内存系统通常使用分页机制,将虚拟页面映射到物理页面。这意味着虚拟内存页的内容可能会被分割成多个物理页面,或者一个虚拟页面可能映射到磁盘上的某个位置。

(3)页表管理: 操作系统通过页表来跟踪虚拟内存页和物理内存页之间的映射关系。每个进程都有自己的页表,用于将虚拟地址转换为物理地址。这意味着虚拟内存页的地址可能与物理RAM地址不同。

(4)内存分配的灵活性: vmalloc() 分配的虚拟内存通常是连续的,但不一定与物理内存页对齐。因此,它们可能会跨越多个物理页面。这使得内核可以更加灵活地管理虚拟内存,不受物理内存的限制。

综上,虚拟内存系统提供了对内存的抽象和管理,允许操作系统将虚拟内存页映射到物理内存页,也可以映射到磁盘上的交换空间。这种抽象和管理机制使得内核可以更灵活地管理内存,但也增加了内存管理的复杂性。因此,虚拟内存页的虚拟地址通常不直接映射到物理RAM地址上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值