第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

相关文章

Python内存管理机制之垃圾回收与引用计数操作全过程

《Python内存管理机制之垃圾回收与引用计数操作全过程》SQLAlchemy是Python中最流行的ORM(对象关系映射)框架之一,它提供了高效且灵活的数据库操作方式,本文将介绍如何使用SQLAlc... 目录安装核心概念连接数据库定义数据模型创建数据库表基本CRUD操作创建数据读取数据更新数据删除数据查

k8s容器放开锁内存限制问题

《k8s容器放开锁内存限制问题》nccl-test容器运行mpirun时因NCCL_BUFFSIZE过大导致OOM,需通过修改docker服务配置文件,将LimitMEMLOCK设为infinity并... 目录问题问题确认放开容器max locked memory限制总结参考:https://Access

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Python内存优化的实战技巧分享

《Python内存优化的实战技巧分享》Python作为一门解释型语言,虽然在开发效率上有着显著优势,但在执行效率方面往往被诟病,然而,通过合理的内存优化策略,我们可以让Python程序的运行速度提升3... 目录前言python内存管理机制引用计数机制垃圾回收机制内存泄漏的常见原因1. 循环引用2. 全局变

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

最新Spring Security的基于内存用户认证方式

《最新SpringSecurity的基于内存用户认证方式》本文讲解SpringSecurity内存认证配置,适用于开发、测试等场景,通过代码创建用户及权限管理,支持密码加密,虽简单但不持久化,生产环... 目录1. 前言2. 因何选择内存认证?3. 基础配置实战❶ 创建Spring Security配置文件

java内存泄漏排查过程及解决

《java内存泄漏排查过程及解决》公司某服务内存持续增长,疑似内存泄漏,未触发OOM,排查方法包括检查JVM配置、分析GC执行状态、导出堆内存快照并用IDEAProfiler工具定位大对象及代码... 目录内存泄漏内存问题排查1.查看JVM内存配置2.分析gc是否正常执行3.导出 dump 各种工具分析4.

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空