Joh*_*ohn 33 language-agnostic memory variables memory-management
当我编写一个程序并告诉它时int c=5,它将值5放入它的内存中,但是它如何记住哪一个?我能想到的唯一方法就是有另外一点记忆来告诉它,但是它必须记住它保存在哪里,所以它如何记住一切都在哪里?
Jen*_*der 13
您的代码在执行之前被编译,在该步骤中,您的变量将被存储值的空间的实际引用替换.
这至少是一般原则.实际上,它将更加复杂,但仍然是相同的基本想法.
这里有很多好的答案,但他们似乎都错过了一个重要的观点,我认为这是OP问题的主要内容,所以这里就是这样.我说的是像C++这样的编译语言,解释的语言要复杂得多.
编译程序时,编译器会检查您的代码以查找所有变量.一些变量将是全局的(或静态的),有些变量将是本地的.对于静态变量,它为它们分配固定的内存地址.这些地址可能是顺序的,它们从某个特定值开始.由于大多数体系结构(以及虚拟内存机制)上的内存分段,每个应用程序都可以(可能)使用相同的内存地址.因此,如果我们假设存储空间程序允许在我们的示例中使用从0开始,则编译的每个程序都将第一个全局变量放在位置0.如果该变量是4个字节,则下一个将位于位置4,这些不会与系统上运行的其他程序冲突,因为它们实际上是在运行时映射到内存的任意顺序部分.这就是为什么它可以在编译时分配固定地址而不用担心遇到其他程序.
对于局部变量,它们不是被赋予固定地址,而是分配了相对于堆栈指针(通常是寄存器)的固定地址.当调用一个在堆栈上分配变量的函数时,堆栈指针只需移动所需的字节数,从而在堆栈的已用字节中创建一个间隙.所有局部变量都被赋予堆栈指针的固定偏移量,将它们放入该间隙.每次使用局部变量时,都会通过添加堆栈指针和偏移量来计算实际内存地址(忽略寄存器中的缓存值).当函数返回时,堆栈指针被重置为调用函数之前的方式,因此包含局部变量的整个堆栈帧可以被下一个函数调用覆盖.
读变量(编程) - 内存分配:http://en.wikipedia.org/wiki/Variable_ (programming)
#Memory_allocation
这里是链接中的文本(如果你不想真正去那里,但是你缺少文本中的所有链接):
变量分配的细节和它们的值的表示在编程语言和给定语言的实现之间变化很大.许多语言实现为局部变量分配空间,其范围持续在调用堆栈上的单个函数调用,并且在函数返回时其内存自动回收.(更一般地说,在名称绑定中,变量的名称绑定到内存中某些特定块(连续序列)的地址,并且变量上的操作操纵该块.对于值大的变量,引用更常见编译代码时的未知大小.这些变量引用值的位置而不是存储值本身,它是从称为堆的内存池中分配的.
绑定变量具有值.然而,价值是一种抽象,一种观念; 在实现中,值由某些数据对象表示,该数据对象存储在计算机存储器中的某处.程序或运行时环境必须为每个数据对象留出内存,并且由于内存是有限的,因此当不再需要对象来表示某个变量的值时,请确保生成此内存以供重用.
必须回收从堆分配的对象 - 尤其是在不再需要对象时.在垃圾收集语言(例如C#,Java和Lisp)中,当现有变量不再引用它们时,运行时环境会自动回收对象.在非垃圾收集语言(如C)中,程序(和程序员)必须显式分配内存,然后释放它,以回收其内存.如果不这样做会导致内存泄漏,在程序运行时堆会耗尽,从而有可能因耗尽可用内存而导致最终失败.
当变量引用动态创建的数据结构时,其某些组件可能只能通过变量间接访问.在这种情况下,垃圾收集器(或缺少垃圾收集器的语言中的类似程序功能)必须处理这样一种情况,即只需要从变量可以访问的部分内存中回收
有一个多步舞蹈变成c = 5机器指令来更新内存中的位置.
编译器分两部分生成代码.有指令部分(加载一个地址为C的寄存器;用文字5加载一个寄存器;存储).并且有一个数据分配部分(在偏移0处留下4个字节的空间用于称为"C"的变量).
"链接加载器"必须以操作系统能够运行它的方式将这些内容放入内存中.加载程序请求内存,操作系统分配一些虚拟内存块.OS还通过一组不相关的管理机制将虚拟内存映射到物理内存.
加载器将数据页放入一个位置,将指令部分放入另一个位置.请注意,指令使用相对地址(数据页的偏移量为0).加载器提供数据页面的实际位置,以便指令可以解析实际地址.
当执行实际的"存储"指令时,操作系统必须查看引用的数据页是否实际位于物理存储器中.它可能位于交换文件中,必须加载到物理内存中.正在使用的虚拟地址被转换为存储器位置的物理地址.