从更底层研究C\C++动态内存分配

以前在学C++ 的时候,一直不懂:动态内存分配的本质,或者更加深入到底层的意义.虽然说,动态内存分配就是,随机在内存中分配一个地址,但是这句话包含的内容实在太多了,不去理解底层的话,无论如何也仅仅停留在表面阶段,永远提高不了.今天下午,突然看到好久以前的QT5,基本半年没研究过了,还是以前没事干瞎做播放器的时候安装的,于是来了兴趣,想玩玩看.

但是,我遇到了一个问题,就是始终不懂QT框架这么设计的核心,或者从操作系统级别来讲,它为什么提供这样的方式?

请看代码,最简单的默认项目;

#include <QApplication>
#include <MainWindow>

 int main(int argc, char *argv[])
 {
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
 }

这是一个最简单的程序:就是显示一个窗口,恐怕很多人已经习以为常了吧.

但是,我此时有问题要问:

#include <QApplication>
#include <MainWindow>

 int main(int argc, char *argv[])
 {
    QApplication a(argc, argv);
    MainWindow *w=new MainWindow;
    w->show();
    return a.exec();
 }

这个程序运行起来,和上面是完全一样的,但是请问:有什么问题?也许很多人一口就说,没问题啊,不就是和上面一样吗?

细心的人发现有不同

:233805_ZLrm_2702126.png233812_fLjA_2702126.png

然后,我们在看一下这个代码:

#include <QApplication>
#include <QPushButton>
#include <mainwindow.h>
#include <QDebug>
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QPushButton bt1;
    QPushButton *bt2=new QPushButton;

    MainWindow w1;
    MainWindow *w2=new MainWindow;
    qDebug() << "bt1:%d " << &bt1;
    qDebug() << "bt2:%d " << bt2;

    qDebug() << "w1:%d " << &w1;
    qDebug() << "w2:%d " << w2;

    return app.exec();
}

我们来测试一下内存分配结果:

234342_5QuA_2702126.png

注意:系统分配法和动态分配法地址长度不一样!

一个用了直接定义法,一个用了指针写法,问题就是:每个人都能说:后面的是动态内存分配,前面的是操作系统分配.还有呢?动态内存分配究竟怎么个分配法?

或许很多人学C++的时候,也是面对这两种写法 很懵逼,貌似一样吧,但是本质又不一样.一直在表面逗留,而深入不到本质去.

我这里,从更加底层开始分析.我们首先从芯片结构来说起.有人觉得C++怎么会和芯片结构有关系?别忘了,C++继承了C的所有.

好了,开始说芯片:我们从最简单的51单片机说起.

下面是百科:

8051是MCS-51系列单片机的典型产品,我们以这一代表性的机型进行系统的讲解。

  8051单片机包含中央处理器、程序存储器(ROM)、数据存储器(RAM)、定时/计数器、并行接口、串行接口和中断系统等几大单元及数据总线、地址总线和控制总线等三大总线,现在我们分别加以说明:

  · 中央处理器:

  中央处理器(CPU)是整个单片机的核心部件,是8位数据宽度的处理器,能处理8位二进制数据或代码,CPU负责控制、指挥和调度整个单元系统协调的工作,完成运算和控制输入输出功能等操作。

  · 数据存储器(RAM):

  8051内部有128个8位用户数据存储单元和128个专用寄存器单元,它们是统一编址的,专用寄存器只能用于存放控制指令数据,用户只能访问,而不能用于存放用户数据,所以,用户能使用的的RAM只有128个,可存放读写的数据,运算的中间结果或用户定义的字型表。

  · 程序存储器(ROM):

  8051共有4096个8位掩膜ROM,用于存放用户程序,原始数据或表格。

  · 定时/计数器(ROM):

  8051有两个16位的可编程定时/计数器,以实现定时或计数产生中断用于控制程序转向。

  · 并行输入输出(I/O)口:

  8051共有4组8位I/O口(P0、 P1、P2或P3),用于对外部数据的传输。

  · 全双工串行口:

  8051内置一个全双工串行通信口,用于与其它设备间的串行数据传送,该串行口既可以用作异步通信收发器,也可以当同步移位器使用。

  · 中断系统:

  8051具备较完善的中断功能,有两个外中断、两个定时/计数器中断和一个串行中断,可满足不同的控制要求,并具有2级的优先级别选择。

  · 时钟电路:

  8051内置最高频率达12MHz的时钟电路,用于产生整个单片机运行的脉冲时序,但8051单片机需外置振荡电容。

  · 时钟电路:

  8051内置最高频率达12MHz的时钟电路,用于产生整个单片机运行的脉冲时序,但8051单片机需外置振荡电容。

  单片机的结构有两种类型,一种是程序存储器和数据存储器分开的形式,即哈佛(Harvard)结构,另一种是采用通用计算机广泛使用的程序存储器与数据存储器合二为一的结构,即普林斯顿(Princeton)结构。INTEL的MCS-51系列单片机采用的是哈佛结构的形式,而后续产品16位的MCS-96系列单片机则采用普林斯顿结构。

注意:234703_v4Co_2702126.png重点在这里.

234737_rNZc_2702126.png

数据存储器?程序存储器?这是什么?和C++动态呢诶村分配又有什么关系?

那我们就来抓一下头绪.

下面是百科,关于程序区和数据区:

C语言可执行代码结构

 名称内容
代码段 可执行代码、字符串常量
数据段 已初始化全局变量、已初始化全局静态变量、局部静态变量、常量数据
BSS段 未初始化全局变量,未初始化全局静态变量
 局部变量、函数参数
 动态内存分配


        一般情况下,一个可执行二进制程序(更确切的说,在Linux操作系统下为一个进程单元,在UC/OSII中被称为任务)在存储(没有调入到内存运行)时拥有3个部分,分别是代码段(text)、数据段(data)和BSS段。这3个部分一起组成了该可执行程序的文件。

        (1)代码段(text segment):存放CPU执行的机器指令。通常代码段是可共享的,这使得需要频繁被执行的程序只需要在内存中拥有一份拷贝即可。代码段也通常是只读的,这样可以防止其他程序意外地修改其指令。另外,代码段还规划了局部数据所申请的内存空间信息。

        代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

        (2)数据段(data segment):或称全局初始化数据段/静态数据段(initialized data segment/data segment)。该段包含了在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据。

        (3)未初始化数据段:亦称BSS(Block Started by Symbol)。该段存入的是全局未初始化变量、静态未初始化变量。

        而当程序被加载到内存单元时,则需要另外两个域:堆域和栈域。图1-1所示为可执行代码存储态和运行态的结构对照图。一个正在运行的C程序占用的内存区域分为代码段、初始化数据段、未初始化数据段(BSS)、堆、栈5个部分。

 

 

图1-1  C语言可执行代码结构

      (4)栈段(stack):存放函数的参数值、局部变量的值,以及在进行任务切换时存放当前任务的上下文内容。

      (5)堆段(heap):用于动态内存分配,即使用malloc/free系列函数来管理的内存空间。

     在将应用程序加载到内存空间执行时,操作系统负责代码段、数据段和BSS段的加载,并将在内存中为这些段分配空间。栈段亦由操作系统分配和管理,而不需要程序员显示地管理;堆段由程序员自己管理,即显示地申请和释放空间。

    另外,可执行程序在运行时具有相应的程序属性。在有操作系统支持时,这些属性页由操作系统管理和维护。

转载于:https://my.oschina.net/xiaoershaoye/blog/1537274

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值