Linux中brk(),sbrk(),mmap(),malloc(),calloc()的异同

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

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

#include <unistd.h>

       int brk(void *end_data_segment);

       void *sbrk(ptrdiff_t increment);

DESCRIPTION
       brk   sets   the   end   of   the   data   segment   to   the value specified by end_data_segment, when that value is reasonable, the system   does   have enough   memory   and   the process does not exceed its max data size (see setrlimit(2)).

       sbrk increments the program's data   space   by   increment   bytes.    sbrk isn't a system call, it is just a C library wrapper.   Calling sbrk with an increment of 0 can be used to find the current location of the   program break.

RETURN VALUE
       On   success,   brk returns zero, and sbrk returns a pointer to the start of the new area.   On error, -1 is returned, and errno is set to ENOMEM.


sbrk不是系统调用,是C库函数。系统调用通常提供一种最小功能,而库函数通常提供比较复杂的功能。

在Linux系统上,程序被载入内存时,内核为用户进程地址空间建立了代码段、数据段和堆栈段,在数据段与堆栈段之间的空闲区域用于动态内存分配。

内核数据结构mm_struct中的成员变量start_code和end_code是进程代码段的起始和终止地址,start_data和 end_data是进程数据段的起始和终止地址,start_stack是进程堆栈段起始地址,start_brk是进程动态内存分配起始地址(堆的起始地址),还有一个 brk(堆的当前最后地址),就是动态内存分配当前的终止地址。

C语言的动态内存分配基本函数是malloc(),在Linux上的基本实现是通过内核的brk系统调用。brk()是一个非常简单的系统调用,只是简单地改变mm_struct结构的成员变量brk的值。

mmap系统调用实现了更有用的动态内存分配功能,可以将一个磁盘文件的全部或部分内容映射到用户空间中,进程读写文件的操作变成了读写内存的操作。在 linux/mm/mmap.c文件的do_mmap_pgoff()函数,是mmap系统调用实现的核心。do_mmap_pgoff()的代码,只是新建了一个vm_area_struct结构,并把file结构的参数赋值给其成员变量m_file,并没有把文件内容实际装入内存。
Linux内存管理的基本思想之一,是只有在真正访问一个地址的时候才建立这个地址的物理映射。

==================================================================================
C语言跟内存分配方式
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运

算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多

C语言跟内存申请相关的函数主要有 alloc,calloc,malloc,free,realloc,sbrk等.其中alloc是向栈申请内存,因此无需释放. malloc分配的内存是位于堆中的,并且没有初始化内存的内容,因此基本上malloc之后,调用函数memset来初始化这部分的内存空间.calloc则将初始化这部分的内存,设置为0. 而realloc则对malloc申请的内存进行大小的调整.申请的内存最终需要通过函数free来释放. 而sbrk则是增加数据段的大小;

malloc/calloc/free基本上都是C函数库实现的,跟OS无关.C函数库内部通过一定的结构来保存当前有多少可用内存.如果程序 malloc的大小超出了库里所留存的空间,那么将首先调用brk系统调用来增加可用空间,然后再分配空间.free时,释放的内存并不立即返回给os, 而是保留在内部结构中. 可以打个比方: brk类似于批发,一次性的向OS申请大的内存,而malloc等函数则类似于零售,满足程序运行时的要求.这套机制类似于缓冲.

使用这套机制的原因: 系统调用不能支持任意大小的内存分配(有的系统调用只支持固定大小以及其倍数的内存申请,这样的话,对于小内存的分配会造成浪费; 系统调用申请内存代价昂贵,涉及到用户态和核心态的转换.
函数malloc()和calloc()都可以用来分配动态内存空间,但两者稍有区别。   
     malloc()函数有一个参数,即要分配的内存空间的大小:    
     void *malloc(size_t size); 
     calloc()函数有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小:   
     void *calloc(size_t numElements,size_t sizeOfElement);
     如果调用成功,函数malloc()和calloc()都将返回所分配的内存空间的首地址。
     malloc() 函数和calloc()函数的主要区别是前者不能初始化所分配的内存空间,而后者能。如果由malloc()函数分配的内存空间原来没有被使用过,则其中的每一位可能都是0;反之,如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。也就是说,使用malloc()函数的程序开始时(内存空间还没有被重新分配)能正常运行,但经过一段时间后(内存空间已被重新分配)可能会出现问题。
     calloc() 函数会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为零;如果你是为指针类型的元素分配内存,那么这些元素通常(但无法保证)会被初始化为空指针;如果你是为实数类型的元素分配内存,那么这些元素可能(只在某些计算机中)会被初始化为浮点型的零。
     malloc() 函数和calloc()函数的另一点区别是calloc()函数会返回一个由某种对象组成的数组,但malloc()函数只返回一个对象。为了明确是为一个数组分配内存空间,有些程序员会选用calloc()函数。但是,除了是否初始化所分配的内存空间这一点之外,绝大多数程序员认为以下两种函数调用方式没有区别:
     calloc(numElements ,sizeOfElement);
     malloc(numElements *sizeOfElement) ;
     需要解释的一点是,理论上(按照ANSIC标准)指针的算术运算只能在一个指定的数组中进行,但是在实践中,即使C编译程序或翻译器遵循这种规定,许多C 程序还是冲破了这种限制。因此,尽管malloc()函数并不能返回一个数组,它所分配的内存空间仍然能供一个数组使用(对realloc()函数来说同样如此,尽管它也不能返回一个数组)。
     总之,当你在calloc()函数和malloc()函数之间作选择时,你只需考虑是否要初始化所分配的内存空间,而不用考虑函数是否能返回一个数组。
     当程序运行过程中malloc了,但是没有free的话,会造成内存泄漏.一部分的内存没有被使用,但是由于没有free,因此系统认为这部分内存还在使用,造成不断的向系统申请内存,是的系统可用内存不断减少.但是,内存泄漏仅仅指程序在运行时,程序退出时,OS将回收所有的资源.因此,适当的重起一下程序,有时候还是有点作用.

sbrk(int incr) 本函数用来增加分配给调用程序的数据段的空间数量,增加incr个字节的空间brk函数的原形是:int    brk(void    *endds) 
   它的功能是:更改数据段空间的分配 
   char    *p; 
   p=malloc(1); 
   这时p指向的内存空间大小是1    byte 
   brk(p+100) 
   这时p指向的内存空间大小是101    bytes

      程式分配虚拟内存也不是你要一个字节就给你一个字节,而是你要一个字节给你一个页面,因为映射物理内存时只能以页为单位。你要另一个字节时,它在这个页面的剩余空间给你。

注意大部份UNIX虚拟内存的使用是只增不减的。

CODE:malloc(32 * 1024) --->;sbrk += 32 * 1024
free()    --->;sbrk 不减少。
但如如果再来一次
malloc(32 * 1024) ---->;sbrk 也不增,使用原有空间.
但对于LINUX来说它是要以内存的最大数收缩的;

CODE:<code>
a = malloc(32 * 1024) -->;sbrk += 32 * 1024
b = malloc(32 * 1024) -->;sbrk += 32 * 1024
if(****){
free(b); --->;sbrk -= 32 * 1024;
}
else{
free(a); --->;sbrk 不减少。只是多了个空洞.
}
</code>
CODE:<code>
/* linux kernel code */
brk()
/*
*   sys_brk() for the most part doesn't need the global kernel
*   lock, except when an application is doing something nasty
*   like trying to un-brk an area that has already been mapped
*   to a regular file.   in this case, the unmapping will need
*   to invoke file system routines that need the global lock.
*/
asmlinkage unsigned long sys_brk(unsigned long brk)
{
unsigned long rlim, retval;
unsigned long newbrk, oldbrk;
struct mm_struct *mm = current->;mm;
down_write(&mm->;mmap_sem);
if (brk < mm->;end_code)
goto out;
newbrk = PAGE_ALIGN(brk);
oldbrk = PAGE_ALIGN(mm->;brk);
if (oldbrk == newbrk)
goto set_brk;
    /******虚拟内存在这里收缩******/
/* Always allow shrinking brk. */
if (brk <= mm->;brk) {
if (!do_munmap(mm, newbrk, oldbrk-newbrk))
goto set_brk;
goto out;
}
/* Check against rlimit.. */
rlim = current->;rlim[RLIMIT_DATA].rlim_cur;
if (rlim < RLIM_INFINITY && brk - mm->;start_data >; rlim)
goto out;
/* Check against existing mmap mappings. */
if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
goto out;
/* Check if we have enough memory.. */
if (!vm_enough_memory((newbrk-oldbrk) >;>; PAGE_SHIFT))
goto out;
/* Ok, looks good - let it rip. */
if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
goto out;
set_brk:
mm->;brk = brk;
out:
retval = mm->;brk; /****这就是返回值*****/
up_write(&mm->;mmap_sem);
return retval;
}
</code>
在LINUX中sbrk(0)能返回比较精确的虚拟内存使用情况,
在SOLARIS/HP中sbrk(0)返回以页为单位的虚拟内存使用情况。使用sbrk(0)来返回程式当前使用了多少内存。

<code>
main(){
int start,end;
start = sbrk(0);
....
malloc(***);
....
end = sbrk(0);
printf("hello I used %d vmemory",end - start);
}

</code>

Astah 9.0升级步骤(Widnows/Mac OS) Astah Professional是一款全新的轻量级UML建模工具。软件集思维导图和UML建模于一体,采用100%纯JAVA构建, 兼容性强,不仅能够实现分布式建模、项目合并,还能够实现和其它建模工具的交互。 阅读详情

相关推荐

EMC系列EtherCAT总线运动控制器(二):Motion通讯连接、总线配置及诊断

雷赛-EMC系列EtherCAT总线运动控制器(二):Motion通讯连接、总线配置及诊断

weixin_38570076的博客 1882

brk和sbrk及内存分配函数相关

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

share8888的专栏 853

Winform美化框架AntdUI中Table的使用方法

使用核心注意点: 数据模型中属性名需要完全与new Column里的列名一致否则添加数据源则无法读取到详细内容。

wevix的博客 3676

sbrk/brk函数用法

sbrk/brk函数重新指定数据段的结束位置 sbrk()

THE YEAR的专栏 1792

PointPainting 复现

三维目标检测

weixin_58207716的博客 4532

告别Vysor!用Scrcpy在Mac上无线投屏安卓手机(附魅族16th闪退修复实战)

本文详细介绍了如何在Mac上配置和使用开源投屏工具Scrcpy,实现安卓手机无线投屏的高效解决方案。从基础环境准备到高级功能调优,包括无线连接配置、输入控制增强、多设备管理和性能优化等实用技巧,特别针对魅族16th等机型的闪退问题提供了修复方案,帮助用户彻底告别Vysor等商业软件。

weixin_28712661的博客 394

brk、sbrk、mmap的区别__2018.04.24

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

weixin_40316053的博客 1691

DIY必备:如何用N-MOS管搭建低成本DC有刷电机驱动电路(附原理图+避坑指南)

本文详细介绍了如何使用N-MOS管搭建低成本、高可靠性的DC有刷电机驱动电路。针对DIY爱好者,从核心原理、电路设计、元件选型到焊接调试,提供了完整的实战指南,并重点解析了续流二极管选型、栅极驱动设计等关键避坑要点,帮助读者成功驱动电机并确保电路稳定运行。

delta的博客 773

内存分配_sbrk,brk

写在前面:小生纯业余选手,开此博仅仅是为了积累,纯当笔记来用。如有看官光临小生博客,请不要相信我的代码就是正确的。如果您发现了错误也恳请耽误您一点时间,请您在下面指出来,不胜感激! 如果发现一些笔记的说法完全是错误的请建议我删除! zai

PC22 813

Monocle2在R 4.3环境下的终极避坑指南:从安装到可视化全流程解析

本文提供了在R 4.3环境下安装和运行Monocle2的完整解决方案,重点解决了依赖包兼容性、源码修改及BEAM分析报错等关键问题。文章详细解析了从环境准备、依赖包处理、源码安装验证到从Seurat对象转换、拟时轨迹构建、高级可视化及性能优化的全流程,旨在帮助用户顺利完成单细胞拟时分析。

weixin_29206669的博客 1353

Unreal5 从入门到精通之 学习Niagara特效系统

UE5 Niagara粒子系统解析 Niagara是UE5中的高性能粒子特效系统,相比传统粒子系统具有完全可编程性和可视化节点编辑两大特点。核心单元发射器(Emitter)分为模板发射器(预设效果如喷泉、火焰)和空白发射器(高度自定义)。系统提供13种预设模板,包括吹飞粒子、五彩纸屑爆发、动态光束等常见特效。 Niagara采用三级模块化设计: 系统级:全局参数设置与更新 发射器级:控制粒子生成规则与行为 粒子级:处理单个粒子的生命周期和渲染 关键模块包括初始化粒子属性、物理模拟、颜色渐变等,支持GPU加速

TxNet 1120

Linux中brk()系统调用,sbrk(),mmap(),malloc(),calloc()的异同

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

kobbee9的专栏 1万+

SAP-MM-采购过账接口(与WMS集成)-代码

1、判断传入值非空检验; 2、判断过账日期是否允许在当前期间; 3、判断是否为集采订单业务,是否审批完成; 4、判断是否发布标准成本发布(此业务场景与价格控制3+S有关) 5、保存日志表; 6、判断业务公司订单审批状态; 7、创建STO交货单、集采公司订单过账、STO公司间创建交货单、交货单过账(两步法)、过账失败回滚(冲销交货、删除交货单、冲销集采入库)

qq_32198063的博客 420

Linux中brk()系统调用,sbrk(),mmap(),malloc(),calloc()的异同【转】

转自:http://blog.youkuaiyun.com/kobbee9/article/details/7397010 brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的: 每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空间,程序中动态分配的空间就是从...

weixin_33894992的博客 114

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

几个函数

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

ryder001的专栏 375

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与Windows下C程序内存布局差异与调试实战

内存布局是理解程序如何在计算机内存中组织与运行的核心概念,它定义了代码、数据、堆栈等关键区域的分配与访问规则。其原理基于虚拟内存机制,为每个进程提供独立且连续的地址空间,确保了隔离性与灵活性。掌握内存布局的技术价值在于,它能帮助开发者从根本上诊断和解决段错误、内存泄漏、堆栈溢出等顽疾,并指导性能优化。在跨平台开发、系统编程、性能调优及安全领域,理解内存模型尤为重要。本文聚焦C语言在Linux与Windows平台的内存布局差异,通过对比分析栈增长方向、堆管理器实现、工具链等关键点,并结合缓冲区溢出、堆破坏等实

weixin_33889245的博客 342

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C/C++内存管理核心机制与高频面试题精讲

内存管理是计算机程序设计的核心基础,它决定了程序如何高效、安全地使用系统内存资源。其原理涉及操作系统对内存的划分与管理机制,如栈、堆、全局区等不同内存区域的生命周期和访问特性。掌握内存管理的技术价值在于能够编写出高性能、高稳定性的系统级软件,避免内存泄漏、野指针等致命错误,这在操作系统、游戏引擎、嵌入式开发等对性能和资源控制要求极高的应用场景中至关重要。本文聚焦于C/C++语言中**内存管理**的实践,深入剖析**智能指针**等现代C++工具如何自动化资源管理,并详解内存分区、操作对比及常见陷阱,为开发者构

weixin_30697239的博客 398

编译错误:In function `_sbrk_r‘:sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk‘

问题描述: GCC编译过程中报错: In function `_sbrk_r': sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk' 原因分析: 底层没有实现某些库函数如:sprintf,snprintf,vsprintf等。 可尝试将部分代码注释以确认到底是哪个函数未实现 解决方案: 添加相应的lib库 ...

Hongggggggg 2836

关于移植jSON编译时报错sbrkr.c:(.text+0xc): undefined reference to `_sbrk'处理

最近有个项目需要用到jSON函数,在移植了jSON后编译报错如下:sbrkr.c:(.text+0xc): undefined reference to `_sbrk'。 通过百度查询知道原来是GCC编译器不支持malloc、free、memcpy、strlen等函数导致的,正常在嵌入式系统开发过程中都会遇到这个问题。 正好这个项目是使用移远M26模块的OpenCPU开发的,好巧不巧的我就遇到...

顾小豆的博客 4383
上一篇: 解决FileZilla不能下载的问题
下一篇: linux perl shell perl vi grep awk xargs 批量替换(转载)
阿磊2013
博客等级 码龄18年 95粉丝 106原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值