1、进程的地址空间(mm_struct结构和vm_area_strcut结构)到底是什么时候被映射的?
进程的地址空间是在进程创建时就被映射的。在Linux系统中,每个进程都有自己的地址空间,包括代码段、数据段、堆栈等。这些地址空间是在进程创建时由操作系统分配和映射的
一个进程的用户地址空间主要由 mm_struct 结构和 vm_area_structs 结构来描述。mm_struct 结构对进程整个用户空间进行描述 。vm_area_structs 结构对用户空间中各个内存区进行描述。
所以当进程被创建的时候,相应的函数/结构也应该被使用
2.什么是内存泄漏?为什么会发生内存泄漏?
内存泄漏是指在程序运行过程中,动态分配的内存没有在使用完毕后被释放,导致这部分内存无法被其他程序使用,造成内存浪费甚至系统崩溃。
内存泄漏的发生原因有多种,常见的包括:
1. 使用 malloc、new 等函数动态分配内存后,没有对应的 free、delete 操作来释放内存。
2. 数组越界访问,使得程序访问了不属于它的内存空间。
3. 野指针:已经释放的内存被再次访问或者没有正确初始化。
4. 单例模式造成的内存泄漏,由于单例的静态特性使得其生命周期和应用的生命周期一样长,如果一个对象已经不再需要使用了,而单例对象还持有该对象的引用,就会使得该对象不能被正常回收,从而导致了内存泄漏。
为了避免内存泄漏,程序员需要确保在分配内存后,使用完毕后一定要及时释放内存,避免不必要的内存占用。
在前面提到的动态内存,因为每次使用完都需要被释放,但存在没有被释放的情况,这时候就相当于系统丢失了一些内存,也就是内存泄漏。
3.什么是野指针?为什么会出现野指针?
野指针是指向位置随机的、不正确的指针,其产生原因主要包括以下几种:
指针变量未初始化:如果指针变量没有初始化,其值是随机的,指向的是不确定的内存。在对其进行了解引用后,结果将是不可知的。
指针释放后未置空:当指针所指向的内存被释放后,如果没有将指针置空,那么这个指针就指向了一个未知的内存。对其解引用将会导致不可预测的行为,严重的情况是如果这个未知的内存恰好被其他程序或操作系统用于存储数据,那么你的程序可能会读取到一些不应该读取到的数据,甚至可能会破坏其他程序或操作系统的数据。
指针操作超出了变量的作用域:比如在函数中返回了局部变量的地址或者引用,因为局部变量出了作用域就释放了,这时候返回的地址指向的内存也是未知的
野指针是指向位置随机,不正确的指针。简单来说就是,这个指针因为操作不当,发生了错误,变成了指向未知数据的指针,野指针
4.通过 mmap()进行内存映射,多进程是否安全?
使用mmap()进行内存映射在多进程环境中是安全的。
在多进程环境中,不同的进程可以拥有自己的地址空间,并且可以通过mmap()函数将文件或设备映射到进程的用户空间中。这样,每个进程都可以直接处理文件或设备的数据,实现了共享内存的目的。
然而,需要注意的是,虽然mmap()提供了进程间共享内存的方式,但是这种直接的访问方式容易导致程序出错,因为映射区域的操作直接影响到文件的内容。此外,映射过多的文件容易导致虚拟内存的压力,进而影响系统的稳定性。
因此,在使用mmap()进行内存映射时,需要谨慎处理映射区域的访问权限和映射数量,确保程序的正确性和稳定性。同时,也需要根据具体的应用场景选择合适的通信机制,以避免不必要的进程间通信开销。
5.用户空间(进程)是否有高端内存概念?
用户空间(进程)没有高端内存概念。在内核空间才存在高端内存。用户进程最多只能访问3G物理内存,而内核进程可以访问所有物理内存。
在32位的Linux内核虚拟地址空间中,0-3G是用户空间,3-4G是内核空间
6. 64位内核中有高端内存吗?
Linux内核高端内存 – Linux Kernel Exploration (ilinuxkernel.com)
目前现实中,64位Linux内核不存在高端内存,因为64位内核可以支持超过512GB内存。若机器安装的物理内存超过内核地址空间范围,就会存在高端内存。
当内核模块代码或线程访问内存时,代码中的内存地址都为逻辑地址,而对应到真正的物理内存地址,需要地址一对一的映射。所以就会存在内核逻辑空间访问0xc0000000 ~ 0xffffffff,那么对应的物理内存范围就为0x0 ~ 0x40000000,即只能访问1G物理内存。有再多的物理内存也访问不了。
因此x86架构中将内核地址空间划分三部分:ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。ZONE_HIGHMEM即为高端内存,这就是内存高端内存概念的由来。
高端内存HIGH_MEM地址空间范围为0xF8000000 ~ 0xFFFFFFFF(896MB~1024MB),当内核想访问高于896MB物理地址内存时,从0xF8000000 ~ 0xFFFFFFFF地址空间范围内找一段相应大小空闲的逻辑地址空间,借用一会。借用这段逻辑地址空间,建立映射到想访问的那段物理内存(即填充内核PTE页面表),临时用一会,用完后归还。这样别人也可以借用这段地址空间访问其他物理内存,实现了使用有限的地址空间,访问所有所有物理内存。
高端内存的最基本思想:借一段地址空间,建立临时地址映射,用完后释放,达到这段地址空间可以循环使用,访问所有物理内存。
事实上,高端内存还存在着划分VMALLOC_START~VMALLOC_END、KMAP_BASE~FIXADDR_START和FIXADDR_START~4G。
对应高端内存的3部分,高端内存映射有三种方式:
映射到”内核动态映射空间”,持久内核映射,临时映射
7.在32 位和 64 位系统上,用户进程能访问多少物理内存?内核代码能访问多少物理内存?
32位系统用户进程最大可以访问3GB,内核代码可以访问所有物理内存。 64位系统用户进程最大可以访问超过512GB,内核代码可以访问所有物理内存。
具体可以看看前面高端内存中的概念
8.在物理内存为 1G 的计算机中,能否调用 malloc(1.6G )?为什么?
malloc能够申请的空间大小与物理内存的大小没有直接关系,仅与程序的虚拟地址空间相关。程序运行时,堆空间只是程序向操作系统申请划出来的一大块虚拟地址空间。应用程序通过malloc申请空间,得到的是在虚拟地址空间中的地址,之后程序运行所提供的物理内存是由操作系统完成的
在物理内存为1G的计算机中,通常不能直接调用malloc(1.6G)。这是因为操作系统对进程的内存分配进行了限制,以防止进程过度消耗内存导致系统不稳定或崩溃。这种限制通常称为内存限制或地址空间限制。
在32位系统中,由于地址空间是有限的(通常为4GB),因此每个进程可用的内存也是有限的。在1G内存的计算机中,即使操作系统允许malloc(1.6G)调用,实际上也无法满足这个请求,因为进程的地址空间不足以容纳这么大的内存块。
在64位系统中,地址空间更大,理论上可以调用malloc(1.6G)。但是,即使计算机有足够的物理内存(1G以上),也并不意味着操作系统会允许分配这么大量的内存给一个进程。操作系统可能会采用各种策略来限制进程的内存使用,例如虚拟内存管理、内存分页等,以控制进程对内存的需求。
因此,虽然在理论上可以调用malloc(1.6G)在64位系统中,但在实际情况下是否可行取决于操作系统的配置、进程的需求以及系统的总体资源使用情况。在大多数情况下,为了系统的稳定性和性能考虑,操作系统会对进程的内存分配进行限制,以确保资源合理利用并避免资源耗尽。