大内高手—内存模型

进程下多线程的内存模型 你是不是也是进程与线程傻傻分不清?内存管理是不是搞得你焦头烂额?一个进程到底能够有多少个线程?不搞清楚誓不罢休! 一.进程与线程 进程:资源(CPU、内存)分配的基本单位。 线程:CPU调度和分配的基本单位。 以上概念似乎耳熟能详,实际到底啥意思却还不知所以然。 首先时进程四要素: 1.有一段程序供其执行,不一定专用,可以与其他进程共用。 2.有专用的内核堆栈空间。 3.在Linux内核中有进程控制块task_struct,供内核调度器识别并参与调度。 4.有独立的用户堆栈空间。 以下为Linux下一个进程 阅读详情
 

大内高手—内存模型

 

转载时请注明出处和作者联系方式:http://blog.youkuaiyun.com/absurd

作者联系方式:李先静 <xianjimli at hotmail dot com>

更新时间:2007-7-9

了解linux的 内存模型,或许不能让你大幅度提高编程能力,但是作为一个基本知识点应该熟悉。坐火车外出旅行时,即时你对沿途的地方一无所知,仍然可以到达目标地。但是 你对整个路途都很比较清楚的话,每到一个站都知道自己在哪里,知道当地的风土人情,对比一下所见所想,旅程可能更有趣一些。

 

类似的,了解linux的内存模型,你知道每块内存,每个变量,在系统中处于什么样的位置。这同样会让你心情愉快,知道这些,有时还会让你的生活轻更松些。看看变量的地址,你可以大致断定这是否是一个有效的地址。一个变量被破坏了,你可以大致推断谁是犯罪嫌疑人。

 

Linux的内存模型,一般为:

地址

作用

说明

>=0xc000 0000

内核虚拟存储器

用户代码不可见区域

<0xc000 0000

Stack(用户栈)

ESP指向栈顶

 

↓

 

↑

 

空闲内存

>=0x4000 0000

文件映射区

 

<0x4000 0000

 

 

↑

 

空闲内存

 

 

Heap(运行时堆)

通过brk/sbrk系统调用扩大堆,向上增长。

 

.data、.bss(读写段)

从可执行文件中加载

>=0x0804 8000

.init、.text、.rodata(只读段)

从可执行文件中加载

<0x0804 8000

保留区域

 

 

很多书上都有类似的描述,本图取自于《深入理解计算机系统》p603,略做修改。本图比较清析,很容易理解,但仍然有两点不足。下面补充说明一下:

 

1.         第一点是关于运行时堆的。

为说明这个问题,我们先运行一个测试程序,并观察其结果:

#include <stdio.h>

 

int main(int argc, char* argv[])

{

    int  first = 0;

    int* p0 = malloc(1024);

    int* p1 = malloc(1024 * 1024);

    int* p2 = malloc(512 * 1024 * 1024 );

    int* p3 = malloc(1024 * 1024 * 1024 );

    printf("main=%p print=%p/n", main, printf);

    printf("first=%p/n", &first);

    printf("p0=%p p1=%p p2=%p p3=%p/n", p0, p1, p2, p3);

 

    getchar();

 

    return 0;

}

 

运行后,输出结果为:

main=0x8048404 print=0x8048324

first=0xbfcd1264

p0=0x9253008 p1=0xb7ec0008 p2=0x97ebf008 p3=0x57ebe008

 

l         main和print两个函数是代码段(.text)的,其地址符合表一的描述。

l         first是第一个临时变量,由于在first之前还有一些环境变量,它的值并非0xbfffffff,而是0xbfcd1264,这是正常的。

l         p0是在堆中分配的,其地址小于0x4000 0000,这也是正常的。

l         但p1和p2也是在堆中分配的,而其地址竟大于0x4000 0000,与表一描述不符。

 

原因在于:运行时堆的位置与内存管理算法相关,也就是与malloc的实现相关。关于内存管理算法的问题,我们在后继文章中有详细描述,这里只作简要说明。在glibc实现的内存管理算法中,Malloc小块内存是在小于0x4000 0000的内存中分配的,通过brk/sbrk不断向上扩展,而分配大块内存,malloc直接通过系统调用mmap实现,分配得到的地址在文件映射区,所以其地址大于0x4000 0000。

 

从maps文件中可以清楚的看到一点:

00514000-00515000 r-xp 00514000 00:00 0

00624000-0063e000 r-xp 00000000 03:01 718192     /lib/ld-2.3.5.so

0063e000-0063f000 r-xp 00019000 03:01 718192     /lib/ld-2.3.5.so

0063f000-00640000 rwxp 0001a000 03:01 718192     /lib/ld-2.3.5.so

00642000-00766000 r-xp 00000000 03:01 718193     /lib/libc-2.3.5.so

00766000-00768000 r-xp 00124000 03:01 718193     /lib/libc-2.3.5.so

00768000-0076a000 rwxp 00126000 03:01 718193     /lib/libc-2.3.5.so

0076a000-0076c000 rwxp 0076a000 00:00 0

08048000-08049000 r-xp 00000000 03:01 1307138    /root/test/mem/t.exe

08049000-0804a000 rw-p 00000000 03:01 1307138    /root/test/mem/t.exe

09f5d000-09f7e000 rw-p 09f5d000 00:00 0          [heap]

57e2f000-b7f35000 rw-p 57e2f000 00:00 0

b7f44000-b7f45000 rw-p b7f44000 00:00 0

bfb2f000-bfb45000 rw-p bfb2f000 00:00 0          [stack]

 

2.         第二是关于多线程的。

现在的应用程序,多线程的居多。表一所描述的模型无法适用于多线程环境。按表一所述,程序最多拥有上G的栈空间,事实上,在多线程情况下,能用的栈空间是非常有限的。为了说明这个问题,我们再看另外一个测试:

#include <stdio.h>

#include <pthread.h>

 

 

void* thread_proc(void* param)

{

    int  first = 0;

    int* p0 = malloc(1024);

    int* p1 = malloc(1024 * 1024);

 

    printf("(0x%x): first=%p/n",    pthread_self(), &first);

    printf("(0x%x): p0=%p p1=%p /n", pthread_self(), p0, p1);

 

    return 0;

}

 

#define N 5

int main(int argc, char* argv[])

{

    int first = 0;

    int i= 0;

    void* ret = NULL;

    pthread_t tid[N] = {0};

 

    printf("first=%p/n", &first);

    for(i = 0; i < N; i++)

    {

        pthread_create(tid+i, NULL, thread_proc, NULL);

    }

 

    for(i = 0; i < N; i++)

    {

        pthread_join(tid[i], &ret);

    }

 

    return 0;

}

 

运行后,输出结果为:

first=0xbfd3d35c

(0xb7f2cbb0): first=0xb7f2c454

(0xb7f2cbb0): p0=0x84d52d8 p1=0xb4c27008

(0xb752bbb0): first=0xb752b454

(0xb752bbb0): p0=0x84d56e0 p1=0xb4b26008

(0xb6b2abb0): first=0xb6b2a454

(0xb6b2abb0): p0=0x84d5ae8 p1=0xb4a25008

(0xb6129bb0): first=0xb6129454

(0xb6129bb0): p0=0x84d5ef0 p1=0xb4924008

(0xb5728bb0): first=0xb5728454

(0xb5728bb0): p0=0x84d62f8 p1=0xb7e2c008

 

我们看一下:

主线程与第一个线程的栈之间的距离:0xbfd3d35c - 0xb7f2c454=0x7e10f08=126M

第一个线程与第二个线程的栈之间的距离:0xb7f2c454 - 0xb752b454=0xa01000=10M

其它几个线程的栈之间距离均为10M。

也就是说,主线程的栈空间最大为126M,而普通线程的栈空间仅为10M,超这个范围就会造成栈溢出。

 

栈溢出的后果是比较严重的,或者出现Segmentation fault错误,或者出现莫名其妙的错误。

 

Innovus中_clock_gen skew group的隐藏陷阱:如何避免自动分组导致的时序问题 本文深入剖析了在Innovus工具进行时钟树综合(CTS)时,`_clock_gen` skew group自动分组机制可能引发的隐蔽时序问题。文章通过实际案例,解释了该机制如何错误地将分频寄存器与配置寄存器归为一组,从而破坏时钟域边界并导致post-CTS时序违例,并提供了关闭自动提取、手动精确定义skew group等有效解决方案。 阅读详情

相关推荐

python基础·练习1(字符串作业)

python基础·练习1字符串作业一、填空二、编程初级中级 字符串作业 一、填空 1.已知s2 = ‘123’,则:s2 * 3 = ___________; s2 + str(456) = ___________; s2 = '123' print(s2 * 3) #123123123 print(s2 + str(456)) #123456 2.已知s1 = ‘123456789’。则: s1[:3] = ________; s1[-5:] =____________; s1[::2]=______;

qq_47326711的博客 8122

linux中内存模型,Linux Memory 理解内存模型

在user space里的内存,大致是这个结构 (1) 代码和常量放在底部的内存里,这是只读的区域。尝试在这个区域写入会造成segmentation fault。(2)底部向上的第二部分是放全局变量和静态变量的内存区,其中更进一步分为了 data segment 和 BSS(Block Started by Symbol )。data segment存放的是初始化的数据,而BSS存放的是未初始化的...

weixin_34430580的博客 489

Cherry Studio部署MCP服务报错全记录:从零解决‘Connection closed‘问题

本文详细记录了在Cherry Studio中部署MCP服务时遇到‘Connection closed’报错的完整排查与解决过程。文章从环境依赖(UV、Bun)的安装验证、绝对路径配置、网络镜像源设置,到服务端手动调试与Cherry Studio配置检查,提供了一套系统性的解决方案,帮助开发者彻底解决此类连接问题。

g9h0i1的博客 761

Linux内存管理源码剖析

Linux 内核 源码 内存管理 钱国正 淮阴师范学院

钱国正的专栏 1487

YOLO-FastestV2从零部署到移动端推理实战手册

本文详细介绍了YOLO-FastestV2从零开始的完整部署流程,涵盖环境搭建、模型训练、格式转换及移动端部署。通过实战步骤,指导开发者将这一轻量级目标检测模型成功部署到Android设备,实现实时推理。文章重点解析了PyTorch到NCNN的模型转换与优化,助力移动端AI应用开发。

l1k9j8h7g6的博客 668

ModbusRTU串口读写报文解析

解析MODBUS报文的格式,讨论异常状态、读多个寄存器与写多个寄存器

Serendipitor的博客 9208

linux内存模型

前面已经分析把物理内存添加到memblock以及给物理内存建立页表映射,这里我们分析内存模型。在Linux内核中支持3种内存模型,分别为 flat memory model Discontiguous memory model sparse memory model 所谓memory model,其实就是从cpu的角度看,其物理内存的分布情况,在linux kernel中,使用什么的方式来管理这些物理内存。某些体系架构支持多种内存模型,但在内核编译构建时只能选择使用一种内存模型。 1. 基本概念 1.

生活需要深度 2558

中山大学_数据科学与计算机_预推免

前言 2019 年 9 月中旬是中山大学预推免时间,本人没能进到夏令营,但是最后在预推免上岸也算不幸中的万幸。 记忆不一定准确,但希望能帮到他人。 想看 流程 的可以直接看总结,正文部分有本人心路历程。 预推免 中山大学的预推免大致可以分为 报道,机试,面试 三大部分,而且尤其是面试,所有人加起来总时长 3 天,幸运的是,本人被安排在第一天的下午第一场,上午就是机试,报道,机试,面试,无缝衔接。 ...

一把健 5208

转载--大内高手—内存模型

大内高手—内存模型 了解linux的内存模型,或许不能让你大幅度提高编程能力,但是作为一个基本知识点应该熟悉。坐火车外出旅行时,即时你对沿途的地方一无所知,仍然可以到达目标地。但是你对整个路途都很比较清楚的话,每到一个站都知道自己在哪里,知道当地的风土人情,对比一下所见所想,旅程可能更有趣一些。 类似的,了解linux的内存模型,你知道每块内存,每个变量,在系统中处于什么样的位置。

技术资料库 2289

如何在白平衡标定种构建不同类型的白平衡色温坐标系

以各家芯片方案的白平衡色温坐标系为切入点,详细介绍了各家芯片色温坐标系构建的理论依旧;并解析了不同色温坐标系下的物理含义,提提出了多种不同的色温坐标系

大熊 959

【短距离通信】【WiFi】精讲802.11n/ac/ax mpdu和ampdu最大长度

在 Wi-Fi 标准(802.11n、802.11ac 和 802.11ax)中,和是数据传输的核心概念。理解它们各自的作用以及不同标准下的最大长度限制,有助于深入了解 Wi-Fi 的性能优化机制。以下是对802.11n802.11ac和802.11ax中MPDU和A-MPDU最大长度的详细技术分析和对比。1. MPDU 和 A-MPDU 的基本概念MPDU 是经过 MAC 层处理后的数据单元,主要由MAC层数据帧和物理层的传输头部(PHY headers)组成。

风云说通信 1107

大内高手 内存模型

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.youkuaiyun.com/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 大内高手—内存模型&a

jggyff的博客 133

Windows10环境下激活虚拟环境报错【source : 无法将“source”项识别为 cmdlet、函数、脚本文件或可运行程序的名称】

在使用Django创建Web程序前,需要创建一个虚拟的工作环境,在使用【source ll_env/bin/activate】命令激活虚拟环境时报错:source : 无法将“source”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。所在位置 行:1 字符: 2。

提供C#相关开发 、云计算、运维测试、网络安全相关技术分享与服务,有意向可联系。 1万+
上一篇: 复杂指针解析
下一篇: 大内高手—栈/堆
trunk0813
博客等级 码龄18年 7粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值