sbrk

操作系统知识整理——Linux下进程的内存布局以及brk()、sbrk()函数探究 文章目录前言一、内存堆栈模型 前言 本篇文章是自己在学习xv6操作系统内核时,发现自己对进程在内存中的布局知识点上还是有一些混淆不清,所以在这里做一些补充整理。 一、内存堆栈模型 参考上图,简要地分类,内存可以分为4个部分,从低地址到高地址分别是: 程序代码区:该区域在程序运行时存放程序的二进制代码。 全局数据区:该区域主要存放全局变量,静态变量和各种常量。 堆:堆用于在程序运行时动态分配内存,比如new一个新的对象,或者malloc一个新数组,就是在堆中分配存储空间的,一般由程序员手动控. 阅读详情

brk() , sbrk() 的声明如下:

  1. #include <unistd.h>   
  2. int brk(void *addr);  
  3. void *sbrk(intptr_t increment);  
这两个函数都用来改变 "program break" (程序间断点)的位置,这个位置可参考下图:

如 man 里说的:

引用
brk()  and  sbrk() change the location of the program break, which defines the end of the process's data segment (i.e., the program break is the first location after the end of the uninitialized data segment). 
brk() 和 sbrk() 改变 "program brek" 的位置,这个位置定义了进程数据段的终止处(也就是说,program break 是在未初始化数据段终止处后的第一个位置)。
如此翻译过来,似乎会让人认为这个 program break 是和上图中矛盾的,上图中的 program break 是在堆的增长方向的第一个位置处(堆和栈的增长方向是相对的),而按照说明手册来理解,似乎是在 bss segment 结束那里(因为未初始化数据段一般认为是 bss segment)。


首先说明一点,一个程序一旦编译好后,text segment ,data segment 和 bss segment 是确定下来的,这也可以通过 objdump 观察到。下面通过一个程序来测试这个 program break 是不是在 bss segment 结束那里:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
 
 
int bssvar;    //声明一个味定义的变量,它会放在 bss segment 中
 
 
int main(void)
{
    char *pmem;
    long heap_gap_bss;
 
 
    printf ("end of bss section:%p\n", (long)&bssvar + 4);
 
 
    pmem = (char *)malloc(32);          //从堆中分配一块内存区,一般从堆的开始处获取
    if (pmem == NULL) {
        perror("malloc");
        exit (EXIT_FAILURE);
    }
 
 
    printf ("pmem:%p\n", pmem);
 
 
//计算堆的开始地址和 bss segment 结束处得空隙大小,注意每次加载程序时这个空隙都是变化的,但是在同一次加载中它不会改变
    heap_gap_bss = (long)pmem - (long)&bssvar - 4;         
    printf ("1-gap between heap and bss:%lu\n", heap_gap_bss);
 
 
    free (pmem);   //释放内存,归还给堆
    
    sbrk(32);        //调整 program break 位置(假设现在不知道这个位置在堆头还是堆尾)
     pmem = (char *)malloc(32);   //再一次获取内存区
        if (pmem == NULL) {
                perror("malloc");
                exit (EXIT_FAILURE);
        }
 
 
        printf ("pmem:%p\n", pmem);   //检查和第一次获取的内存区的起始地址是否一样
    heap_gap_bss = (long)pmem - (long)&bssvar - 4;  //计算调整 program break 后的空隙
    printf ("2-gap between heap and bss:%lu\n", heap_gap_bss);
 
 
    free(pmem);   //释放
    return 0;
}

下面,我们分别运行两次程序,并查看其输出:


引用
[beyes@localhost C]$ ./sbrk  
end of bss section:0x8049938
pmem:0x82ec008
1-gap between heap and bss: 2762448
pmem:0x82ec008
2-gap between heap and bss: 2762448
[beyes@localhost C]$ ./sbrk  
end of bss section:0x8049938
pmem:0x8dbc008
1-gap between heap and bss: 14100176
pmem:0x8dbc008
2-gap between heap and bss: 14100176


从上面的输出中,可以发现几点:
1. bss 段一旦在在程序编译好后,它的地址就已经规定下来。
2. 一般及简单的情况下,使用 malloc() 申请的内存,释放后,仍然归还回原处,再次申请同样大小的内存区时,还是从第 1 次那里获得。
3. bss segment 结束处和堆的开始处的空隙大小,并不因为 sbrk() 的调整而改变,也就是说明了 program break 不是调整堆头部。

所以,man 手册里所说的  “program break 是在未初始化数据段终止处后的第一个位置” ,不能将这个位置理解为堆头部。这时,可以猜想应该是在堆尾部,也就是堆增长方向的最前方。下面用程序进行检验:

当 sbrk() 中的参数为 0 时,我们可以找到 program break 的位置。那么根据这一点,检查一下每次在程序加载时,系统给堆的分配是不是等同大小的:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
 
 
int main(void)
{
        void *tret;
        char *pmem;
 
 
 
        pmem = (char *)malloc(32);
        if (pmem == NULL) {
                perror("malloc");
                exit (EXIT_FAILURE);
        }
 
 
        printf ("pmem:%p\n", pmem);
 
        tret = sbrk(0);
        if (tret != (void *)-1)
                printf ("heap size on each load: %lu\n", (long)tret - (long)pmem);
 
 
    return 0;
}

运行上面的程序 3 次:

引用
[beyes@localhost C]$ ./sbrk  
pmem:0x80c9008
heap size on each load: 135160
[beyes@localhost C]$ ./sbrk  
pmem:0x9682008
heap size on each load: 135160
[beyes@localhost C]$ ./sbrk  
pmem:0x9a7d008
heap size on each load: 135160
[beyes@localhost C]$ ./sbrk  
pmem:0x8d92008
heap size on each load: 135160
[beyes@localhost C]$ vi sbrk.c

从输出可以看到,虽然堆的头部地址在每次程序加载后都不一样,但是每次加载后,堆的大小默认分配是一致的。但是这不是不能改的,可以使用 sysctl 命令修改一下内核参数:

引用
#sysctl -w kernel/randomize_va_space=0

这么做之后,再运行 3 次这个程序看看:

引用
[beyes@localhost C]$ ./sbrk  
pmem:0x804a008
heap size on each load: 135160
[beyes@localhost C]$ ./sbrk  
pmem:0x804a008
heap size on each load: 135160
[beyes@localhost C]$ ./sbrk  
pmem:0x804a008
heap size on each load: 135160

从输出看到,每次加载后,堆头部的其实地址都一样了。但我们不需要这么做,每次堆都一样,容易带来缓冲区溢出攻击(以前老的 linux 内核就是特定地址加载的),所以还是需要保持 randomize_va_space 这个内核变量值为 1 。

下面就来验证 sbrk() 改变的 program break 位置在堆的增长方向处:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
 
 
int main(void)
{
        void *tret;
        char *pmem;
        int i;
        long sbrkret;
 
       pmem = (char *)malloc(32);
        if (pmem == NULL) {
                perror("malloc");
                exit (EXIT_FAILURE);
        }
 
 
        printf ("pmem:%p\n", pmem);
 
         for (i = 0; i < 65; i++) {
                sbrk(1);
                printf ("%d\n", sbrk(0) - (long)pmem - 0x20ff8);   //0x20ff8 就是堆和 bss段 之间的空隙常数;改变后要用 sbrk(0) 再次获取更新后的program break位置
        }
       free(pmem);
 
       
       return 0;
}

运行输出:

引用
[beyes@localhost C]$ ./sbrk  
pmem:0x804a008
1
2
3
4
5

... ...
61
62
63
64


从输出看到,sbrk(1) 每次让堆往栈的方向增加 1 个字节的大小空间。

而 brk() 这个函数的参数是一个地址,假如你已经知道了堆的起始地址,还有堆的大小,那么你就可以据此修改 brk() 中的地址参数已达到调整堆的目的。

实际上,在应用程序中,基本不直接使用这两个函数,取而代之的是 malloc() 一类函数,这一类库函数的执行效率会更高。 还需要注意一点,当使用 malloc() 分配过大的空间,比如超出 0x20ff8 这个常数(在我的系统(Fedora15)上是这样,别的系统可能会有变)时,malloc 不再从堆中分配空间,而是使用 mmap() 这个系统调用从映射区寻找可用的内存空间。

 

转载至: http://blog.youkuaiyun.com/ssjhust123/article/details/7772153
malloc的底层实现(ptmalloc) 前言 本文主要介绍了ptmalloc对于内存分配的管理。结合网上的一些文章和个人的理解,对ptmalloc的实现原理做一些总结。 内存布局 介绍ptmalloc之前,我们先了解一下内存布局,以x86的32位系统为例: 从上图可以看到,栈至顶向下扩展,堆至底向上扩展, mmap 映射区域至顶向下扩展。 mmap 映射区域和堆相对扩展,直至耗尽虚拟地址空间中的剩余区域,这种结构便于 C 运行时库使用... 阅读详情

相关推荐

【存储管理】brk()系统调用

尽管应用程序编程时很少直接调用brk()系统调用

博客已搬家 2965

brk(), sbrk() 用法详解

brk() , sbrk() 的声明如下: #include int brk(void *addr); void *sbrk(intptr_t increment); 这两个函数都用来改变 "program break" (程序间断点)的位置,这个位置可参考下图: 如 man 里说的: 引用 brk()  and  sbrk() change the location of

__七把刀__ 3万+

但是我看见newlib源码中有关于_sbrk_r和_sbrk的源码实现,我该链接什么库可以直接使用?

在newlib源码中,确实包含了_sbrk_r和_sbrk的实现,但这些实现通常是空的占位符或依赖于具体平台的底层支持(例如裸机环境或操作系统)。newlib是一个可移植的 C 库,设计上允许用户根据目标平台提供自定义实现,而不是直接提供一个通用的_sbrk实现。因此,即使源码中有相关代码,你不能直接链接某个库来“直接使用”_sbrk,而需要根据你的嵌入式环境(例如裸机 ARM Cortex-M)提供适当的实现或链接正确的对象文件。

qq_46635513的博客 1007

brk和sbrk

program break 是虚拟内存中数据段的结束位置, malloc 通过调用 brk 或 sbrk 增加 program break 的值,从而创建可以通过 malloc 动态分配的内存空间。:进程可以通过增加堆的大小来分配内存,堆是一段长度可变的连续虚拟内存,始于进程的未初始化数据段末尾,随着内存的分配和释放而增减。在计算机程序中,“program break”通常指的是堆的当前内存边界。都是用来改变程序的“program break”的位置,也就是改变数据段的长度,实现虚拟内存到物理内存的映射。

我的博客 1912

【底层机制】剖析 brk 和 sbrk的底层原理

brk 和 sbrk 就是用来操作这个 Program Break 的系统调用

沐怡旸的专栏 907

内存控制brk和sbrk

内存控制brk和sbrk 比malloc更底层的内存控制,适合“内存空间大小不定”的场景,效率比malloc更高 函数原型 #include &amp;amp;amp;amp;amp;lt;unistd.h&amp;amp;amp;amp;amp;gt; int brk(void *addr); void *sbrk(intptr_t increment); 相关概念:通常将内存边界称为 program break 程序段 在program break的位置抬升后,程序可以访.

湖心岛 843

brk, sbrk 函数

NAME        brk, sbrk - change data segment size SYNOPSIS        #include ;        int brk(void *end_data_segment);        void *sbrk(ptrdiff_t increment); DESCRIPTION        brk  sets

xiaoguifufu的专栏 2824

企业微信群机器人配置全攻略:从零到消息推送的完整流程

本文详细介绍了企业微信群机器人的配置与使用全流程,从零开始指导如何创建机器人、获取Webhook地址,到通过HTTP请求发送文本、Markdown、图片及模板卡片等多种消息类型。内容涵盖核心的接口配置、安全实践及实战应用场景,帮助开发与运维团队快速构建自动化消息推送中枢,提升协作效率。

weixin_29231725的博客 842

malloc底层原理 brk,sbrk,mmap

是 Linux 提供的一种。,从而影响 malloc()增加了 4KB 的堆空间。只能扩展堆,无法释放。

zjkyeah的博客 1384

Fiddler everywhere的一些基础操作

网上能搜到的Fiddler everywhere使用教程太少,于是我整理了一些自己实操成功的内容,包括Fiddler everywhere的Mock测试、弱网测试等基础操作,后续还会持续更新。操作系统:macOS使用工具:Fiddler everywhere 5.10.0本文简单介绍了使用Fiddler everywhere进行的Mock测试和弱网测试,而Fiddler everywhere提供了更多的其他实用的功能,我会在后期进行一个持续的学习和更新。

weixin_44346646的博客 2479

你的OLED屏和MPU6050为啥通信失败?从IIC的7位地址冲突讲起

本文深入解析OLED屏与MPU6050传感器在I2C总线上的通信故障,重点探讨7位地址冲突问题。通过分析I2C协议中的地址分配机制,提供硬件调整和软件调试的完整解决方案,帮助开发者有效排查和解决设备无响应问题。

weixin_26876073的博客 151

brk sbrk函数

 NAME       brk, sbrk - change data segment sizeSYNOPSIS       #include ;       int brk(void *end_data_segment);       void *sbrk(ptrdiff_t increment);DESCRIPTION       brk  sets  the  end  of  the  d

6627

节卡Jaka Zu APP编程避坑指南:从频繁通讯错误到稳定Socket交互的调试心得

本文详细解析了节卡Jaka Zu APP编程中常见的通讯错误问题,并提供了从基础排查到高级调试的完整解决方案。通过优化网络配置、固件匹配、心跳机制和数据交互规范,开发者可实现稳定的Socket通讯,有效提升工业机器人操控的可靠性。文章特别针对v1.6.7.3版本的典型问题给出了实用调试技巧。

weixin_42639633的博客 325

sbrk和brk的区别

brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的: 每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从 这一块分配的。如果这块空间不够,malloc函数族(realloc,calloc等)就调用sbrk函数将数据段的下界移动,sbrk函数在内核的管 理下将虚拟地址空间映

u012420933的专栏 2565

快乐8 Ai大模型XGBoost LightGBM预测系统

随机森林回归:通过集成多个决策树模型,提高预测的准确性和稳定性。XGBoost:一种基于梯度提升的强大模型,擅长处理结构化数据。LightGBM:一种高效的基于决策树算法的分布式梯度提升框架,具有快速的训练速度和低内存消耗。高预测准确率:通过集成多种模型,提供更为精准的预测结果。多种预测方法:支持同尾号、重号、温号、连号和综合预测等多种预测策略,满足不同用户的需求。实时日志:在预测过程中,用户可以实时查看系统的预测进度和结果。

m0_72636583的博客 1万+

高速电路的信号完整性分析

摘要:介绍了高速PCB设计中的信号完整性概念以及破坏信号完整性的原因,从理论和计算的层面上分析了高速电路设计中反射和串扰的形成原因,并介绍了IBIS仿真。 关键词:信号完整性 反射 串扰 IBIS仿真 随着半导体技术和深压微米工艺的不断发展,IC的开关速度目前已经从几十MHz增加到几百MHz,甚至达到几GHz。在高速PCB设计中,工程师经常会碰到误触发、阻尼振荡、过冲、欠冲、串...

bh_wang的专栏 1431

brk 和 sbrk 区别

转自:https://www.cnblogs.com/chengxuyuancc/p/3566710.html brk和sbrk的定义,在man手册中定义了这两个函数: 1 #include <unistd.h> 2 int brk(void *addr); 3 void *sbrk(intptr_t increment);   手册上说brk...

weixin_30682415的博客 944

YOLOv8与UNetV2融合:一种面向目标检测与图像分割的混合方法【附核心代码】

我们提出了一种基于YOLOv8和UNetV2相结合的混合架构。该架构利用YOLOv8作为主干进行目标检测,同时在YOLOv8的特征提取过程中,引入UNetV2来进行图像分割任务的增强。在该架构中,YOLOv8负责大范围目标检测和位置预测,而UNetV2则在检测网络的特征图基础上,通过其高效的上下文信息提取和细节恢复能力,进一步优化分割任务。在本文中,我们提出了一种改进YOLOv8的方法,通过引入图像分割网络UNetV2来提高图像分割检测性能。

一键难忘的博客 3525

brk()/sbrk()

brk() brk()调整数据段的end位置 #define_GNU_SOURCE #include<unistd.h> int brk(viod * end_data_segment); 参数 end_data_segment:将数据段的end置于end_data_segment处 返回值 成功,返回0 失败,-1,返回ENOMEM。 sbrk() sbrk()是一个c语言封装库函数,不是system call,作用通过调整process break的位置,调整bss段?heap的大小

weixin_41540614的博客 544

OBYC自动科目确定整理

WGI是用来重估发货的,通过比较发货时的价格和最新计算的价格,以此将所有差异过账到分配给此事务码的总账科目。是工厂还是公司,一般项目中都是使用工厂,使用工厂的意思就是物料在每个工厂下有一个价格,如果使用公司,则一个公司下的所有工厂都使用一个价格。如果该物料用的是移动平均价,那么该库存依然还存在的情况下,这个价格差异会过账到存货科目上而不会过账到存货的价格差异科目上。用于确定存货评估过账的存货冲抵科目。事务码WGR是用来重估工厂收货的,根据 计算出来的价格差异,把库存的调整过账分配给这个事务码中的总账科目。

nopicture的博客 349

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Linux下brk、sbrk实现一个简易版本的malloc

全局数据区:该区域主要存放全局变量,静态变量和各种常量。

qq_56999918的博客 2347

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

sbrk/brk的用法

sbrk/brk: brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的:     每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从这一块分配的。如果这块空间不够,malloc函数族(realloc,calloc等)就调用sbrk函数将数据段的下界移动,sbrk函数在

继续微笑lsj 1861

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

brk()和sbrk()函数的使用

根据上一篇文章继续解释 brk和sbrk的定义   在man手册中定义了这两个函数:   1 #include 2 int brk(void *addr); 3 void *sbrk(intptr_t increment);     手册上说brk和sbrk会改变program break的位置,program break被定义为程序data segment的结束位置。感

鱼思故渊的专栏 8698

sbrk() 函数是干什么的?

brk和sbrk主要的工作是实现虚拟内存到内存的映射. 在GNU C中,内存分配是这样的:       每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从这一块分配的。如果这块空间不够,malloc函数族(realloc,calloc等)就调用sbrk函数将数据段的下界移动,sbrk函数在内核的

guilanl的专栏 1万+

brk() 与 sbrk()

brk() , sbrk() 的声明如下: [cpp] view plaincopy #include    int brk(void *addr);   void *sbrk(intptr_t increment);   这两个函数都用来改变 "program break" (程序间断点)的位置,这个位置可参考下图:

小小鸟 1273
上一篇: 同步异步阻塞非阻塞
下一篇: vc 命令行下运行
sooolo
博客等级 码龄17年 95粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值