程序中对象和变量的引用如何工作?

时间:2019-01-30 20:41:11

标签: object memory-management reference stack heap

免责声明:我不是一个非常有经验的人,很多问题可能看起来很愚蠢或措辞不好。

我听说过堆栈和堆,并阅读了一些有关它们的内容,但是还有一些我不太了解的事情:

  • 程序如何找到空内存以在物理内存中存储新变量/对象。
  • 程序如何知道对象在内存中的开始位置和对象在何处结束。使用数字变量,我可以想象内存中提供了一些额外的信息,这些信息显示了porgram变量占用了多少位,但是如果我错了,请更正我。
  • 这类似于我的第一个问题,但是:当变量的值仅由零表示时,程序如何将其与可用内存混淆?
  • 对象值null表示对象的地址是一堆0,还是该对象在一点上都没有指向任何东西?如果是这样,以后如何存储“引用”以为其分配地址?

2 个答案:

答案 0 :(得分:1)

  

程序如何找到空内存以在物理内存中存储新变量/对象。

物理内存由OS管理,该OS知道内存的哪些部分由进程使用,哪些部分可用。当需要内存时,程序会要求操作系统使用部分内存。如果此内存用于堆,则需要额外的操作。操作系统通过称为页面的固定大小的块来提供内存。由于页面为4 KB,如果用户malloc的某些字节,则需要优化内存使用,知道页面的哪些部分已使用或可用,并需要在连续{{1} }和malloc。有特定的数据结构来描述使用的空间和查找空间的算法,同时避免碎片。

  

程序如何知道对象在内存中的开始位置和对象在何处结束。使用数字变量,我可以想象到内存中提供了一些额外的信息,这些信息显示了porgram变量占用了多少位,但是如果我错了,请纠正我

程序知道每个变量的地址(即开始)。对于全局变量或静态变量,当链接器将var放入内存时,它由链接器生成。对于局部变量,处理器具有在给定堆栈位置的情况下对其进行计算的装置。对于分配的变量,在分配内存时将其存储在另一个变量(指针)中。关于结束,它取决于变量的类型。对于已知类型(如free)或已知类型的组合(如int s),可以在编译时进行计算。在其他情况下,程序无法知道实体大小。例如,像struct这样的声明可以描述一个数组,但是程序无法知道数组的大小。程序员必须跟踪此信息,例如,通过在另一个变量中写入数组中的元素数。

  

这类似于我的第一个问题,但是:当变量的值仅由零表示时,程序如何将其与可用内存混淆?

该程序从不查看内存以了解其是否空闲。它通过其他方式进行管理(请参阅问题1)。

  

对象值是否为null表示对象的地址是一堆0,还是该对象在一点上都没有指向任何东西?如果是这样,以后如何存储“引用”以为其分配地址?

除了内存的地址“ 0”外,地址永远不会为零。内容设置为零。实际上,不可能读取或写入地址0。它会生成“总线错误”异常(也许您已经遇到过)。指向零地址与“几乎什么都没有指向”完全一样,如果在程序中遇到,则会产生错误。这些变量保存其他变量(指针)的地址。因此,指针的地址定义明确。可能未定义的是它所指向的。可以通过为指针分配某些内容(例如,返回的int * a或另一个变量的地址)来修改它。

答案 1 :(得分:1)

  

程序如何找到空内存以在物理内存中存储新变量/对象。

现代操作系统使用逻辑地址转换。进程看到一系列逻辑地址-它的地址空间。系统硬件将地址范围分为几页。页面的大小取决于系统,并且通常是可配置的。操作系统管理将逻辑页面映射到相同大小的物理页面框架的页面表。

地址空间分为页面范围,即所有进程共享的系统空间和用户空间,而页面空间通常是每个进程唯一的。

在用户空间和系统空间内,页面可能有效或无效。无效的页面尚未映射到进程地址空间。大多数页面可能无效。

总是从操作系统映像页面分配内存。操作系统将具有系统服务,该服务将无效页面转换为有效页面,并映射到物理内存。为了映射页面,操作系统需要查找(或应用程序需要指定)无效的页面范围,然后必须分配物理页面框架以映射到那些页面。请注意,物理页面框架不必连续映射到逻辑页面。

您提到堆栈和堆。堆栈和堆只是内存。操作系统无法确定内存是堆栈,堆还是其他东西。用于内存分配的用户模式库(例如那些实现malloc / free的库)在页面中分配内存以创建堆。使该内存成为堆的唯一原因是有一个堆管理器来控制它。然后,堆管理器可以从分配给堆的页面中分配较小的内存块。

堆栈更简单。它只是页面的连续范围。通常,创建线程或进程的操作系统服务将为堆栈分配一定范围的页面,并将硬件堆栈指针寄存器分配给堆栈范围的高端。

  

程序如何知道对象在内存中的开始位置和对象在何处结束。使用数字变量,我可以想象到内存中提供了一些额外的信息,这些信息可以显示porgram变量占用了多少位,但是如果我错了,请纠正我。

这取决于如何创建程序以及如何在内存中创建对象。对于类型化语言,链接器将变量绑定到地址。链接器还生成用于将那些地址映射到地址空间的指令。对于堆栈/自动变量,编译器会生成指向堆栈的指针的偏移量。调用函数/子例程时,编译器生成代码以分配过程所需的内存,只需通过从堆栈指针中减去就可以了。只需将值添加回堆栈指针即可释放内存。

对于无类型语言(例如汇编语言或Bliss),程序员必须跟踪每个位置的类型。当内存是动态的时,程序员还必须跟踪类型。大多数编程语言通过使用带有类型的指针来帮助解决这一问题。

  

这类似于我的第一个问题,但是:当变量的值仅由零表示时,程序如何将其与可用内存混淆?

可用内存无效。访问可用内存会导致硬件异常。

  

对象值是否为null表示对象的地址是一堆0,还是该对象在一点上都没有指向任何东西?如果是这样,以后如何存储“引用”以为其分配地址?

链接器定义程序的用户地址空间的初始状态。大多数链接器不映射第一页(甚至不超过一页)。该页面无效。正如您所说,这意味着空指针绝对不引用任何内容。如果尝试取消引用空指针,通常会得到某种访问冲突异常

大多数操作系统将允许用户映射第一页。一些链接器将允许用户覆盖默认设置并映射第一页。这并不常见,因为这会使检测内存错误变得困难。