我正在尝试学习操作系统。目前我在虚拟寻址。什么书说如果我们有一个static variable
和一个local variable
并且我们更新它们并睡眠一段时间并尝试打印它们的地址,那么在多个这样的进程中运行一个将获得相同的内存地址。
这是因为每个进程都感觉它具有整个内存并且无法控制物理内存,因此在同时运行的各个进程中地址将保持相同。我理解这一点,但是当我运行我的程序时,我在静态变量中获得相同的地址,但在局部变量中有所不同。凭借我的小操作系统知识,我无法理解为什么会发生这种情况。这是我的代码
int staticvar = 0;
int main(int argc, char const *argv[])
{
int localvar = 0;
staticvar += 1;
localvar += 1;
sleep(10);
printf("static address: %x, value: %d\n", &staticvar, staticvar );
printf("static address: %x, value: %d\n", &localvar, localvar );
return 0;
}
当我同时运行三个不同的进程时,这是我的输出。
./a.out
static address: 60104c, value: 1
static address: 67c6128c, value: 1
./a.out
static address: 60104c, value: 1
static address: 89e2c11c, value: 1
./a.out
static address: 60104c, value: 1
static address: 226e03dc, value: 1
答案 0 :(得分:1)
局部变量分配在被调用函数的堆栈帧上。堆栈帧通过堆栈指针(SP)寄存器引用,该寄存器在启动过程时由OS初始化。该程序使用SP动态分配堆栈空间并查找存储在那里的值。因此,这种类型的访问准备使用动态地址,并且知道操作系统可以选择初始化进程的堆栈帧,无论它在当前上下文中哪个最适合。
另一方面,“静态”变量通常由编译(汇编)代码中的常量地址引用。这就是为什么他们必须驻留在已知的编译时位置。编辑:
正如有人指出的那样,SP的值会因程序执行而改变,具体取决于堆栈的使用情况。因此,如果从程序的不同部分调用相同的函数,则局部变量的地址每次甚至可能不同。
答案 1 :(得分:0)
首先,您定义的int staticvar = 0;
称为global variable
,而不是真正的静态变量。要定义静态变量,您必须在声明变量时添加static
关键字,例如static int staticvar
现在,如果您看到C
文件的汇编代码,您会注意到staticvar
在编译时已被引用。这就是原因,你一直看到staticvar
的内存位置相同。如果您还定义了全局/静态变量,则同样如此。
但是,局部变量获取运行时在stack
中保留的内存,OS内核将控制该内存。这就是为什么你在每次运行时都会看到不同的内存位置。
即使您未在代码中添加sleep()
,此行为仍然有效。
.file "test11.c"
.local staticvar
.comm staticvar,4,4
.section .rodata
.align 8
.LC0:
.string "static address: %x, value: %d\n"
.LC1:
.string "local address: %x, value: %d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movq %rsi, -32(%rbp)
movl $0, -4(%rbp)
movl staticvar(%rip), %eax
addl $1, %eax
movl %eax, staticvar(%rip)
movl -4(%rbp), %eax
addl $1, %eax
movl %eax, -4(%rbp)
movl $3, %edi
movl $0, %eax
call sleep
movl staticvar(%rip), %edx
movl $.LC0, %eax
movl $staticvar, %esi
movq %rax, %rdi
movl $0, %eax
call printf
movl -4(%rbp), %edx
movl $.LC1, %eax
leaq -4(%rbp), %rcx
movq %rcx, %rsi
movq %rax, %rdi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-11)"
.section .note.GNU-stack,"",@progbits