第4部分 库与运行库---(10)内存

2024-05-11 13:48
文章标签 内存 部分 运行库

本文主要是介绍第4部分 库与运行库---(10)内存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

###################
# 10、内存
###################
# 程序的内存布局
在32位操作系统中,内存空间拥有4GB的寻址能力。操作系统会把高地址的空间分配给内核,称为内核空间。
默认情况下,Windows将高地址的2GB空间分配给内核,Linux将高地址的1GB空间分配给内核。剩下的2GB或3GB的内存空间称为用户空间。
在用户空间里,有许多地址区间有特殊的地位,一般来讲,应用程序使用的内存空间里有如下"默认"的区域。
栈:用于维护函数调用的上下文。栈通常在用户空间的最高地址处分配,通常有数兆字节的大小。
堆:用来容纳应用程序动态分配的内存区域,malloc或new分配内存时,得到的内存来自堆里。堆通常存在于栈的下方(低地址方向),可以有几十或数百兆字节。
可执行文件映像:存储着可执行文件在内存里的映像,由装载器在装载时将可执行文件的内存读取或映射到这里。
保留区:对内存中受到保护而禁止访问的内存区域的总称。
栈向低地址增长,堆向高地址增长。当栈或堆现有的大小不够用时,它将按照图中的增长方向扩大自身的尺寸,直到预留的空间被用完为止。

Q:程序出现"段错误(segment fault)" 或者 "非法操作,该内存地址不能read/write" 的错误信息,这是怎么回事?
A:非法指针解引用造成的错误,指针指向一个不允许读或写的内存地址,而程序却试图利用指针来读或写该地址的时候,就会出现这个错误。
最普遍原因有两种:
(1)将指针初始化为NULL,之后没有给它一个合理的值就开始使用指针。
(2)没有初始化栈上的指针,指针的值一般会是随机值,之后就开始使用指针。

# 栈与调用惯例
经典的操作系统里,栈总是向下增长的,栈中的数据是先入后出。
栈顶:由esp的寄存器进行定位,压栈的操作使栈顶的地址减少,弹出的操作使栈顶地址增大。
栈指针:ebp寄存器,ebp寄存器指向了函数活动记录的一个固定位置。

栈保存了一个函数调用所需要的维护信息,常被称为堆栈帧或 活动记录。堆栈帧一般包括如下几方面内容:
(1)函数的返回地址和参数。
(2)临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。
(3)保存的上下文:包括在函数调用前后需要保持不变的寄存器。

在参数之后的数据(包括参数)就是当前函数的活动记录, ebp固定在图中所示的位置,不会随这个函数的执行而变化。
esp始终指向栈顶,随着函数的执行,esp会不断变化。
固定不变的ebp可以用来定位函数活动记录中的各个数据,在ebp之前首先是这个函数的返回地址,它的地址是ebp-4,再往前是压入栈中的参数,它们的地址分别是ebp-8、ebp-12等,视参数数量和大小而定。
ebp所直接指向的数据是调用该函数前ebp的值(Old EBP),这样在函数返回的时候,ebp可以通过读取这个值恢复到调用前的值。

# 堆与内存管理
栈上的数据在函数返回时就会被释放掉,所以无法将数据传递至函数外部。而全局变量没有办法动态地产生,只能在编译的时候定义。
堆是一块巨大 的内存空间,程序可以请求一块连续内存,并自由地使用,这块内存在程序主动放弃之前都会一直保持有效。
第3行用malloc申请了1000个字节的空间之后,程序可以自由地使用这1000个字节,直到程序用free函数释放它。
int main()
{char *p = (char*)malloc(1000);free(p);
}
程序的运行库:管理着堆空间的分配,相当于是向操作系统"批发"了一块较大的堆空间,然后"零售"给程序用。当全部"售完"或程序有大量的内存需求时,再根据实际需求向操作系统"进货"。
Linux下的两种堆空间分配的方式:即两个系统调用,一个是brk()系统调用,另一个是mmap()。
brk()的作用就是设置进程数据段的结束地址,即它可以扩大或者缩小数据段。
brk()的作用实际上就是设置进程数据段的结束地址,即它可以扩大或者缩小数据段(Linux下数据段和BSS合并在一起统称数据段)。
mmap()的作用就是向操作系统申请一段虚拟地址空间,这块虚拟地址空间可以映射到某个文件,当它不将地址空间映射到某个文件时,又称这块空间为匿名空间。
#include <unistd.h>int brk(void *addr);

这篇关于第4部分 库与运行库---(10)内存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/979705

相关文章

NameNode内存生产配置

Hadoop2.x 系列,配置 NameNode 内存 NameNode 内存默认 2000m ,如果服务器内存 4G , NameNode 内存可以配置 3g 。在 hadoop-env.sh 文件中配置如下。 HADOOP_NAMENODE_OPTS=-Xmx3072m Hadoop3.x 系列,配置 Nam

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

JVM内存调优原则及几种JVM内存调优方法

JVM内存调优原则及几种JVM内存调优方法 1、堆大小设置。 2、回收器选择。   1、在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM。   2、对JVM内存的系统级的调优主要的目的是减少

JVM 常见异常及内存诊断

栈内存溢出 栈内存大小设置:-Xss size 默认除了window以外的所有操作系统默认情况大小为 1MB,window 的默认大小依赖于虚拟机内存。 栈帧过多导致栈内存溢出 下述示例代码,由于递归深度没有限制且没有设置出口,每次方法的调用都会产生一个栈帧导致了创建的栈帧过多,而导致内存溢出(StackOverflowError)。 示例代码: 运行结果: 栈帧过大导致栈内存

理解java虚拟机内存收集

学习《深入理解Java虚拟机》时个人的理解笔记 1、为什么要去了解垃圾收集和内存回收技术? 当需要排查各种内存溢出、内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就必须对这些“自动化”的技术实施必要的监控和调节。 2、“哲学三问”内存收集 what?when?how? 那些内存需要回收?什么时候回收?如何回收? 这是一个整体的问题,确定了什么状态的内存可以

NGINX轻松管理10万长连接 --- 基于2GB内存的CentOS 6.5 x86-64

转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=190176&id=4234854 一 前言 当管理大量连接时,特别是只有少量活跃连接,NGINX有比较好的CPU和RAM利用率,如今是多终端保持在线的时代,更能让NGINX发挥这个优点。本文做一个简单测试,NGINX在一个普通PC虚拟机上维护100k的HTTP

笔记整理—内核!启动!—kernel部分(2)从汇编阶段到start_kernel

kernel起始与ENTRY(stext),和uboot一样,都是从汇编阶段开始的,因为对于kernel而言,还没进行栈的维护,所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。         内核起始部分代码被解压代码调用,前面关于uboot的文章中有提到过(eg:zImage)。uboot启动是无条件的,只要代码的位置对,上电就工作,kern

PHP原理之内存管理中难懂的几个点

PHP的内存管理, 分为俩大部分, 第一部分是PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用的层面的管理. 而第二部分就是今天我要介绍的, zend_alloc中描写的关于PHP自身的内存管理, 包括它是如何管理可用内存, 如何分配内存等. 另外, 为什么要写这个呢, 因为之前并没有任何资料来介绍PHP内存管理中使用的策略, 数据结构, 或者算法. 而在我们

string字符会调用new分配堆内存吗

gcc的string默认大小是32个字节,字符串小于等于15直接保存在栈上,超过之后才会使用new分配。

PHP内存泄漏问题解析

内存泄漏 内存泄漏指的是在程序运行过程中申请了内存,但是在使用完成后没有及时释放的现象, 对于普通运行时间较短的程序来说可能问题不会那么明显,但是对于长时间运行的程序, 比如Web服务器,后台进程等就比较明显了,随着系统运行占用的内存会持续上升, 可能会因为占用内存过高而崩溃,或被系统杀掉 PHP的内存泄漏 PHP属于高级语言,语言级别并没有内存的概念,在使用过程中完全不需要主动申请或释放内