内存管理

我们编写的程序在我们看来是一段段的语言,那么在计算机看来我们的代码又是什么样的呢?这就涉及到了编译器如何对代码进行排序的问题。

其他编译环境不是很清楚,这里就以我最熟悉的VC编译器说明。

32位的cpu最大访问能力是4G,编译器在编译代码时将文本和数据编译到指定的区域中。其中低2G作为客户独占区用以存储程序中的代码文本和数据段,高2G作为共享内核分区作为系统代码区。在最低的64k作为保护区,不能够向里面写东西。我们常常碰到禁止访问,冲突代码0x00000005等错误提示。这就是我们的程序中出现空指针而我们调用它的情况。我们在调试时,查看 的内存中的数据用到的地址也是这个地址。我们常常称其为内存地址,这应该是不准确的。我们正常的静态编译程序是不涉及到内存的,只是我们把它想象成内存。

文本代码如果在连接中发生错误,可以通过map文件来查看错误,这是个很实用的技巧哦!具体查看后面再叙述。

紧接着就是我们最关心的数据段了。从低地址到高地址依次是初始化全局变量,未初始化全局变量,堆和栈。用图形表示可以很清楚的看明白,我已经画了图形,但是这个这个网站我传不上来。只能靠大家自己脑补了。

我通过测试(利用int型的数据测试的)发现很有意思的是。初始化全局段的全局变量是从低地址到高地址成长的,而未初始化全局变量段的全局变量和栈中的临时变量是从高地址到低地址倒着生长的,而最奇葩的是堆中的变量是低到高的随机性生长的。另外,全局变量是紧密排列的,而栈中是预留有一定的空间的。这个策略是内存管理中为了最大程度的利用内存空间。

这里必须要讲到的一个是数组越界也就是指针越界的问题了。那么数组越界会导致什么情况呢?假如我声明了一个int a[10]的数组,那么当我访问a[10]会有什么后果呢?我今天特意试了试,发现还蛮有意思的。

首先a[10]会以a的类型继续访问紧接着的空间,程序并不会报错。即使访问a[12]也是如此,据一个大牛讲这是C++与Java的区别。那么什么情况下会报错呢?如果我要对a[10]作为等号的左边进行赋值,那么系统将会报错。但是将a[10]作为等号右边作加减运算并赋值不会出现错误。我认为这是c++编译环境认为这个地址的内容没有被声明为变量,那么编译器将它看做了一个常量。

那么数组越界会发生什么风险呢?首先,最大的风险就是越界的指针或者数组能够修改其越界指向的内存中的内容。有可能造成整个系统的崩溃。这种错误常常是不容易发掘的。

在C++编译环境里,栈通常是很小的。一把设定在1M左右,如果栈的内容超出这个值,程序将无法成功运行。这里我有一个疑问是栈是静态分配的为什么等到运行时才会出现错误?不过可以通过修改将栈的上限调大。

在程序运行时,而二进制文件是被映射到内存中的。为了提高cpu利用率,加速从硬盘中考入内存,操作系统引入了虚拟内存的概念。虚拟内存是指内存的页放在硬盘上的空间。是否是由于虚拟内存采用了和内存同样的分页办法导致的拷贝速度变快呢?这里我还不太清楚了解。

编译环境常常将文本放在0x00401000这个偏移地址处,通常前10位作为页目地址,中10位作为页表地址,最后12位作为偏移地址来映射物理地址和上述讲到的内存地址。这种动态的地址翻译技术带来了复杂度,但是好处也是显而易见的。这样做将有效避免内存利用率不高的问题,还能共享内存。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值