说道“内存地址“

提到计算机性能,内存总是特别关注得一项,那么内存究竟在操作系统里是怎么被玩得呢,脱离不了“内存地址”这个东西。内存地址在计算机系统中扮演着重要的角色,因为它们允许程序在需要时直接访问和操作内存中的数据。通过使用不同的内存地址,计算机可以存储和管理程序的指令、变量、对象和其他数据结构。本文就来说道说道。

什么是内存地址?

内存地址是计算机中用于唯一标识和访问内存中特定位置的一种数值。在计算机的内存系统中,每个存储单元都有一个唯一的地址,类似于房屋的门牌号码。

内存地址通常是一个整数值,用于指示内存中的特定位置。在现代计算机系统中,内存地址通常以字节为单位进行编址,每个字节都有一个唯一的地址。例如,一个32位的计算机系统可以有2^32个不同的内存地址,每个地址对应一个字节。

通过使用内存地址,计算机可以准确地定位和访问内存中的数据。当程序需要读取或写入特定的内存位置时,它可以使用该位置的内存地址来执行相应的操作。

程序是如何获取到内存地址得?

在程序执行过程中,当需要为变量、对象或数据结构分配内存时,计算机系统通过内存管理机制来分配内存地址。一般来说,内存的分配可以分为静态分配和动态分配两种方式。

静态分配:在编译时或程序加载时,编译器或链接器将为程序中的静态变量和全局变量分配内存空间,并分配固定的内存地址。这些变量的内存地址在程序的整个生命周期内都保持不变

动态分配:对于动态分配内存的情况,程序在运行时需要根据需要动态分配和释放内存空间。主要有两种常见的动态分配方式:

   - 堆内存分配:程序可以使用特定的内存分配函数(例如C语言中的`malloc()`或C++中的`new`)来向堆(heap)请求一块特定大小的内存空间。堆是一块动态分配的内存区域,它的内存地址由操作系统动态分配,并通过一个指针返回给程序。程序可以使用该指针来访问和管理分配的内存。当程序不再需要这块内存时,应该使用对应的释放函数(例如`free()`或`delete`)将其返回给堆供其他程序使用。

   - 栈内存分配:栈(stack)是另一种用于分配内存的方式。在函数调用过程中,每当一个函数被调用时,系统会为该函数分配一块栈帧(stack frame),用于存储该函数的局部变量和临时数据。栈是一种后进先出(LIFO)的数据结构,每个栈帧在栈上按顺序排列,通过栈指针来管理。栈帧的分配和释放是由系统自动完成的,无需显式的程序调用。

操作系统怎么分配内存,如何辨别哪些地址可用

在操作系统中,内存分配是通过内存管理单元(MMU)来实现的。MMU是负责将逻辑地址转换为物理地址的硬件组件。下面是一般的内存分配过程:

1) 初始化内存:当计算机启动时,操作系统会对物理内存进行初始化,并建立内存管理数据结构来跟踪内存的分配情况。

2)空闲内存列表:操作系统通常会维护一个空闲内存列表,用于记录可用的内存块。这个列表可以是一个链表、位图或其他数据结构。初始情况下,整个物理内存都被认为是可用的。

3)内存分配算法:当应用程序请求内存时,操作系统会使用特定的内存分配算法来确定分配给应用程序的内存块。常见的内存分配算法包括首次适应、最佳适应和最差适应等。

4)地址空间:操作系统将每个进程的地址空间划分为多个页面或段,每个页面或段具有固定大小。操作系统使用页表或段表来映射逻辑地址和物理地址之间的关系。

5)地址转换:当应用程序引用内存时,生成的逻辑地址会被传递给MMU。MMU使用页表或段表来将逻辑地址转换为物理地址。如果逻辑地址对应的页面或段已经分配给应用程序,则MMU将其转换为对应的物理地址。

6)标记已使用的内存:一旦操作系统分配了内存给应用程序,它会更新空闲内存列表,将已分配的内存从列表中移除,并在内存管理数据结构中标记相应的内存块为已使用状态。

7)内存释放:当应用程序释放内存时,操作系统将内存块重新标记为空闲,并更新空闲内存列表。

空闲内存列表在哪存着?

空闲内存列表通常存储在操作系统的内存管理数据结构中。这个数据结构可以是一个链表、位图、树或其他形式,用于跟踪哪些内存块当前是空闲的。

具体而言,内存管理数据结构可能包含以下信息:

1)内存块的起始地址和大小:用于标识每个内存块的位置和大小。

2)空闲/已分配标记:用于标识每个内存块是空闲还是已经分配给应用程序。

3)邻接关系:记录相邻内存块之间的关系,以便在合并空闲块时进行优化。

内存管理数据结构通常保存在内核内存中,以便操作系统可以随时访问和更新它。这个数据结构可能会在内存中占用一定的空间,但这个开销相对于整个物理内存来说是比较小的。通过查询内存管理数据结构,操作系统可以迅速查找可用的内存块,并将其分配给应用程序。

看到这里就不由得想到:内存空闲表本身肯定是占空间得,那究竟占多少呢?会不会影响对资源的有效利用?

内存空闲表的大小通常与以下因素相关:

1)内存管理算法:不同的内存管理算法(如分区分配、页表等)可能需要不同类型和数量的元数据来管理内存。这些元数据通常包括空闲块的起始地址、大小和状态等信息。不同的算法可能使用不同的数据结构来表示空闲表,如链表、二叉树、位图等,这将影响空闲表的占用空间大小。

2)内存块的数量和大小:空闲表的大小通常与内存块的数量和大小成正比关系。如果系统中有大量的小内存块,则空闲表可能需要更多的条目来跟踪每个内存块的状态。相反,如果系统中存在大块的内存块,则空闲表可能较小。

3)内存分配的粒度:内存管理系统可能将内存划分为不同的粒度,例如字节、页、块等。内存分配粒度的选择将影响空闲表的大小。较小的分配粒度可能需要更多的空闲表条目,而较大的分配粒度可能需要较少的条目。

分配空间,程序释放空间应该会产生内存空间碎片化,无法分配连续性地址。操作系统是如何解决内存空间碎片化问题得?

内存空间碎片化是指内存中存在大量的零散、不连续的空闲内存块,这可能导致无法满足某些需要连续内存的应用程序的内存分配请求。操作系统采取了几种策略来解决内存空间碎片化问题:

内存紧缩(Memory Compaction):内存紧缩是一种将已分配的内存块重新组织、整理的技术。当大量的内存块被释放时,操作系统可以尝试将它们合并,形成更大的连续内存块,从而减少碎片化。这可以通过将已分配的内存块移动到一侧,或者通过重新排列内存块的位置来实现。

内存分区(Memory Partitioning):操作系统可以将物理内存分成多个固定大小的分区,例如页框或段。每个分区可以被独立管理,当应用程序需要连续内存时,操作系统会尽量在同一个分区中分配内存,从而减少碎片化的影响。

内存回收和合并:当应用程序释放内存时,操作系统会及时回收这些内存块,并尝试与相邻的空闲内存块合并,形成更大的连续空闲块。这可以通过合并相邻空闲块的起始地址和大小来实现。

动态内存分配算法:操作系统中的动态内存分配算法(例如伙伴系统或slab分配器)可以通过合并和拆分内存块来优化内存空间的使用。这些算法可以根据当前的内存使用情况进行动态调整,以减少碎片化。

伙伴系统(Buddy System)是一种内存分配和管理算法,用于解决动态内存分配中的外部碎片问题。它是一种基于二进制分割和合并的策略,通常应用于操作系统的内存管理中。

伙伴系统将可用的内存空间划分为不同大小的块,每个块的大小是2的幂次方。例如,系统可能有2KB、4KB、8KB等大小的块。初始时,整个可用内存空间是一个最大块,通常为系统的总内存大小。

当应用程序请求分配一定大小的内存时,伙伴系统会根据请求的大小找到一个大小适当的块来分配。如果找到的块比请求的大小稍大,系统会将该块一分为二,并将其中一部分作为分配给应用程序的内存块,而另一部分则作为可用的空闲块。

这个分割的过程会一直进行,直到找到大小与请求相等的块或者找不到足够大的空闲块为止。如果找不到大小合适的空闲块,系统可能会进行内存回收或者通过合并邻近的空闲块来满足请求。

伙伴系统的优点是能够有效地利用内存,并减少外部碎片。由于每个块的大小都是2的幂次方,因此可以很容易地进行分割和合并操作。然而,伙伴系统也存在一些缺点,例如内部碎片和空间浪费,以及在高并发情况下可能导致的内存分配的争用。

SLAB分配器的基本原理是将内存划分为一组固定大小的SLAB块,每个SLAB块用于存储特定类型的内核对象。每个SLAB块包含一个或多个连续的内存页,用于存储对象数据和管理信息。

SLAB分配器维护三个主要的SLAB链表:

1)Full SLABs:这个链表包含已满的SLAB块,其中所有的对象都已被分配。这些对象可以直接分配给请求者,而无需额外的内存分配操作。

2)Partial SLABs:这个链表包含部分被分配的SLAB块。它们可能还有一些未分配的对象,但仍然有可用的空间。当新的对象需要分配时,它们可以直接从这些SLAB块中获取,而不需要分配新的内存页。

3)Empty SLABs:这个链表包含完全未分配的SLAB块。它们没有任何对象分配给它们,因此可以用于分配新的对象。

当应用程序请求内核对象的分配时,SLAB分配器首先在Partial SLABs链表中查找与请求对象类型匹配的SLAB块。如果找到匹配的SLAB块,则从该块中分配一个对象。如果Partial SLABs链表为空,分配器会将一个Empty SLABs链表中的SLAB块移动到Partial SLABs链表,并分配一个对象。如果Empty SLABs链表也为空,分配器会分配一个新的内存页,创建一个新的SLAB块,并将其添加到Partial SLABs链表。

当释放内核对象时,对象会被返回到对应的SLAB块,并标记为可用。如果SLAB块变为空闲状态,它会从Partial SLABs链表移动到Empty SLABs链表。

SLAB分配器的优势在于它减少了内存碎片和额外的内存分配开销。由于SLAB块是固定大小的,并且对象分配是在SLAB级别进行的,因此可以提高内存分配的效率。此外,SLAB分配器还可以通过高速缓存SLAB块来进一步提高性能。

作为一名从事多年Java开发得老码农,此刻在怀疑JVM是不是干了操作系统本该做得事?

答案是肯定得,JVM在某种程度上类似于操作系统,它负责管理Java程序的内存。通过垃圾回收器(Garbage Collector)来自动管理Java程序中的内存分配和释放,以避免程序员手动管理内存的复杂性和潜在的错误。

JVM的内存管理与操作系统的内存管理有些相似,但也存在一些差异和特定的机制。下面是JVM中的一些内存管理方面的关键概念:

1)Java堆(Java Heap):Java堆是JVM管理的主要内存区域,用于存储Java对象实例。它是一个运行时数据区域,由垃圾回收器负责自动分配和回收内存。

2)栈(Stack):与操作系统的堆栈(stack)不同,JVM的栈用于存储方法调用和局部变量等数据。每个线程在运行时都有自己的栈,栈中的内存是按照后进先出(LIFO)的方式进行管理【有没有想到栈溢出时,异常栈中最后调得一个方法出现在最上面】。

3)方法区(Method Area):方法区用于存储类的信息、静态变量、常量池等数据。它是所有线程共享的内存区域,类似于操作系统中的静态存储区。

4)垃圾回收(Garbage Collection):JVM的垃圾回收器负责自动回收不再使用的对象和释放内存空间。垃圾回收器通过标记-清除、复制、标记-整理等算法来管理堆内存,以减少内存碎片化和优化内存使用。

既然JVM功底这么深厚,还需要依赖操作系统去与物理内存交互吗?JVM与操作系统之间还有哪些内存地址方面得交互?

其实JVM与操作系统之间在内存地址方面的交互还涉及以下几点:

1)虚拟地址到物理地址的转换:JVM使用虚拟地址来访问内存,而操作系统负责将虚拟地址转换为物理地址。这个转换过程通常是通过操作系统的内存管理单元(MMU)来完成的。JVM将虚拟地址传递给MMU,然后MMU使用页表或段表等机制将虚拟地址映射为物理地址。

2) 内存分配和释放:JVM在需要分配内存给Java对象时会向操作系统请求内存。操作系统负责分配物理内存给JVM,并返回分配的起始地址。当Java对象不再使用时,JVM会通知操作系统释放相应的内存。这个过程中,JVM与操作系统之间会有一定的交互和协作。

3)内存管理机制的协调:JVM的垃圾回收器与操作系统的内存管理机制需要相互协调。JVM的垃圾回收器负责标记和回收不再使用的对象,并释放相应的内存。然而,底层的操作系统可能还有自己的内存管理机制,例如操作系统的页面交换或内存回收策略。JVM需要与操作系统协作,以确保两者之间的内存管理不会相互冲突。

4)内存权限和保护:操作系统负责管理内存的权限和保护机制,以确保不同进程或应用程序之间的内存隔离和保护。JVM作为一个应用程序运行在操作系统之上,必须遵守操作系统所定义的内存权限规则,并通过操作系统提供的接口来管理和操作内存。

提到逻辑地址和物理地址这么俩概念,有没有特想知道这俩地址究竟长啥样子?

逻辑地址(Logical Address)是由程序使用的地址空间,是相对于进程或程序的视角而言的。是一个虚拟地址,对应于程序中的变量、数据结构或指令的位置。逻辑地址是在程序中使用的抽象概念,与具体的物理内存位置无关。

举个例子,假设我们有一个简单的程序,声明了一个整数变量x和一个指针变量p。在程序中,我们可以通过逻辑地址引用这些变量,如下所示:

int x = 42;
int* p = &x;

*p = 10;

在这个例子中,逻辑地址用于表示程序中变量x和指针p的位置。在这个抽象层面上,我们不需要关心这些变量在物理内存中的实际位置。

物理地址(Physical Address)是实际的内存地址,对应于计算机内存中的特定位置。它是计算机硬件层面的地址,用于访问和存储数据。物理地址是真实存在的内存位置,用于直接与内存模块进行交互。假设有一台计算机,内存大小为4GB(2^32个地址)。在这个计算机中,物理地址可以用一个32位的二进制数表示。假设变量x被分配到物理地址0x1000,指针p存储了0x1000的值。在这种情况下,物理地址用于直接访问内存中的特定位置。

逻辑地址和物理地址之间的映射是由操作系统的内存管理单元(MMU)来处理的。MMU负责将逻辑地址转换为物理地址,以实现程序的正常执行和内存访问的保护。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不爱运动的跑者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值