C++内存管理结构

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

 C++内存管理结构

 mainCRTStartup 的头几步工作是初始化一些预定义的全局变量, _osplatform, _winmajor, _winminor, _osver, _winver等与Windows Version 有关的. 然后很重要的一步就是初始化 Heap. 大多的内存都是 Heap 上分配的, 如 new, malloc. 所以必须要先初始化才能干别的. 这个函数是_heap_init. 以前的Compiler 有些用自己的 Heap 管理, 但是现在我手上的 Visual Studio .NET 2003, 完全是用的 Windows 系统提供的 Heap management. 所以 _heap_init 很简单:

int __cdecl _heap_init (int mtflag)
{
    // Initialize the "big-block" heap first.
    if ( (_crtheap = HeapCreate( mtflag ? 0 : HEAP_NO_SERIALIZE,
    BYTES_PER_PAGE, 0 )) == NULL )
    return 0;
    ...
}

系统默认的 new, malloc 等等的分配都是在这个_crtheap 上进行的. 试试写个简单的程序: 

int main()
{
    int* p = new int;
    return 0;
}

在int* p = new int; 这一行设个断点, 调试进去. 可以看见new 是这样的: 

void * operator new( size_t cb )
{
    void *res = _nh_malloc( cb, 1 );
    ...
    return res;
}

下面以Debug version为例, 因为Debug version比较有意思. _nh_malloc 只是简单调用_nh_malloc_dbg, 而malloc 也是调用_nh_malloc_dbg来完成内存分配. 

_nh_malloc_dbg最终调用_heap_alloc_dbg, 在这里进行真正的分配工作. Debug Version中, 实际分配的是这样一个结构: 

typedef struct _CrtMemBlockHeader
{
    struct _CrtMemBlockHeader * pBlockHeaderNext;
    struct _CrtMemBlockHeader * pBlockHeaderPrev;
    char * szFileName;
    int nLine;
    size_t nDataSize;
    int nBlockUse;
    long lRequest;
    unsigned char gap[nNoMansLandSize];
    /* followed by:
    * unsigned char data[nDataSize];
    * unsigned char anotherGap[nNoMansLandSize];
    */
} _CrtMemBlockHeader;

假如你要分配一个大小为100的块, 则实际分配的块结构如下: 

_CrtMemBlockHeader + <You Data> (100 bytes) + gap[nNoMansLandSize]

_CrtMemBlockHeader 最后有个gap[nNoMansLandSize], 这个nNoMansLandSize目前的值是 4, 所以在你的数据前后各有4个字节的 gap. _heap_alloc_dbg会把 <Your Data> 的所有字节置为 0xCD, 前后的gap置成 0xFD. 如果你在自己的Data里写, 不小心越了界(前面或者后面), 系统在delete的时候通过检查 gap 的数据是否已被破坏,就知道你有没有越界. 当然了, 如果你恰好写的都是0xFD, 那就没法知道了. 试试如下程序: 

int* p = new int;
p[1] = 0;
delete p;

在Debug 下运行时,delete 时系统会报错: DAMAGE: after normal block (#59) at 0x00375C80. 

_heap_alloc_dbg 调用 Windows System Call HeapAlloc 完成分配. HeapAlloc返回的指针, 要先初始化 _CrtMemBlockHeader. 这个 Header 中有前后两个指针, 事实上所有的内存块连接在一起形成一个双向链表. 在 delete 或者 free 的时候, 链表指针需要调整. 如果没有内存泄漏, 程序结束的时候链表应该为空. 否则说明有内存泄漏. 如下面的程序: 

#include <stdio.h>
#include <stdlib.h>
#include <crtdbg.h>

int main()
{
    int* p = new int;
    //delete p;

    void *px = malloc(100);
    free(px);

    _CrtDumpMemoryLeaks();
    return 0;
}

_CrtDumpMemoryLeaks 通过检查分配链表, 来查找是否有泄漏. 在 Debug 下编译并且在 VC 中跟踪运行, 最后在 VC 的 Output 中会有如下输出: 

Detected memory leaks!
Dumping objects ->
{58} normal block at 0x00375FC0, 4 bytes long.
Data: < > CD CD CD CD 
Object dump complete.

这里只有分配的序号, 还不能知道到底是哪一行程序产生的泄漏. 但是注意看_CrtMemBlockHeader, 事实上它还能记录源程序文件名和行号. 在 MFC 里就利用了这个技术. 在 afx.h 里, 有如下声明:

// Memory tracking allocation
void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
#define DEBUG_NEW new(THIS_FILE, __LINE__)

同时,使用 MFC 时产生的 cpp 文件开始都有如下定义:

#ifdef _DEBUG
#define new DEBUG_NEW

这个 afx 的 new operator 把 new 时发生的源文件和行号传给 _malloc_dbg .这样在 Dump memory leak 的时候就可以同时知道泄漏的数据最初是在什么地方分配的. 

delete 和 free 最终都是用的 _free_dbg. _free_dbg 首先检查前后的 gap 有没有被破坏, 然后把该块从链表中去掉, 最后把数据块全部置成 0xDD.这样如果你不小心使用了已经被删除的数据时,通常数据已经被破坏而出错.

以上说的都是 Debug Version. 如果是 Release version, 内存分配更简单, 没有任何 overhead, 系统直接调用 HeapAlloc 分配所需的内存块. 同时分配的内存块也不会被初始化为 0xCD.
精通C++内存管理:从零开始构建与释放“结构体指针数组” 本文通过一个学生信息管理案例,详细讲解了C++结构体嵌套一级指针的内存管理技术。主要内容包括:1. 使用Person**创建指针数组管理多个Person对象;2. 分层次动态分配内存(指针数组→Person对象→name字符串);3. 严格遵循"由内而外"的释放顺序;4. 完整演示了内存分配、使用和释放的全过程。该案例展示了C++手动内存管理的核心思想,强调精准控制内存分配/释放顺序的重要性,为理解更复杂的内存管理机制打下基础。 阅读详情

相关推荐

深入解析C++结构体指针与内存管理

本文探讨了C++结构体和指针的内存管理问题。通过一个示例代码,分析了常见错误:结构体定义冗余、指针未初始化导致悬空指针问题。给出了解决方案:正确初始化指针、使用智能指针替代new/delete、避免using namespace std等现代C++实践。文章强调了指针初始化和现代内存管理技术的重要性,帮助开发者避免常见陷阱,提高代码健壮性。

2501_90323865的博客 50

C++ Dump 内存快照的实现

C++ Dump 内存快照的实现 近来在工作中总是会有一些dump文件需要分析,但是自己对windug不是很熟。找了些资料程序完成。

46、C/C++编程中的内存管理、循环优化与结构应用

本文探讨了C/C++编程中的内存管理、循环优化和结构应用等关键主题。首先,介绍了在Oracle RDBMS中处理大型嵌套对象的方法,包括拦截内存分配和释放操作,并利用Boehm GC进行垃圾回收。其次,分析了MSVC和GCC编译器在循环优化方面的不同策略,以及如何通过结构代替数组、使用未指定大小的数组来提高代码效率。此外,还讨论了结构版本控制和原始序列化的实际应用场景,例如读取和修改经典游戏“Block out”的高分文件。最后,总结了这些技术的优缺点及适用场景,为开发者提供了实用的编程建议。

chair的专栏 53

C++内存管理体系

C++内存管理体系

流星雨的博客 251

C++内存管理框架?

具体也说不清为什么,一直对C++语言很着迷,即使现在很少使用。做应用系统,讲究的是RAD,不是用Java平台就是.Net平台。C++已经退居幕后,用来做那些高效的,安全的,或需要更强控制功能的程序,比如底层的引擎,硬件相关的或平台级的程序。就像很多已经消失的东西,有一天C++也会消失(我会伤心的)。 C++在堆上分配的内存是由开发者自己控制的,对于复杂逻辑或者应用一些模式时,内存管理可能会

timersun的专栏 1418

C/C++动态内存管理(超详解)

对C和C++11动态内存管理概念,函数,应用场景等的详细介绍

Dai_renwen的博客 2703

C++动态内存管理

问题: 1.string和sizeof的区别 2.malloc、calloc和realloc的区别 3.malloc和new的区别与联系 一、C/C++程序运行起来后,内存分布情况 为什么操做系统设计的时候,需要将完整的内存空间化分成不同的区域? 方便对内存空间进行管理。 如上图: 1.栈又叫做堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。 2.内存映射段是高效的I/O映射方式,用于装载一个共享内存的动态内存库。用户可使用系统接口创建共享内存,用于进程间通信。

一个计算机爱好者学习历程 3416

C++内存管理结构体内存释放

C++中使用new和delete申请和释放内存空间,二者是成对出现的,缺一不可。使用new开辟的内存空间位于堆中,只能通过delete释放,这与局部变量不同,局部变量存储在栈中,变量生存周期结束后其内存也随之释放。    结构体中成员变量中存在指针的,其内存释放遵循从里向外的原则,即先释放成员变量的内存,然后在释放结构体指针。由于C++中允许结构体中使用构造函数和析构函数,构造函数对成员数据进行初

cqhaotian的专栏 2万+

C++内存管理与数据结构深入解析

本文深入探讨了C++内存管理与数据结构的相关知识,包括指针数组、动态内存分配、内存泄漏等问题,并介绍了使用智能指针、二维向量等技术来优化内存使用,同时通过代码示例加深理解。

weixin_42230607的博客 284

C++内存管理和数据结构的应用

本文将深入探讨C++编程中的内存管理以及数据结构的实现和应用,包括动态内存分配、数组操作、链表、栈和队列的实现。我们将通过具体的编程示例,理解如何在C++中高效地处理数据,以及如何通过自定义的数据结构来优化程序的性能。

weixin_42599558的博客 399

C++内存管理与数据结构深入探讨

本文深入探讨了C++中的内存管理和数据结构,包括静态和动态内存分配的区别、内存分配器的使用以及如何通过结构体和联合体实现复杂的数据处理。

weixin_42153793的博客 273

深入理解数据结构与C/C++内存管理

本文深入探讨了数据结构的基本原则以及在C/C++内存管理的机制。通过一系列的自我审查问题,引导读者理解稀疏矩阵的存储、时间空间复杂度、算法性能分析、大O符号、数据结构的定义等关键概念。文章还详细介绍了C语言中的内存分配方式,包括静态和动态内存分配的区别,以及如何使用malloc、calloc、realloc和free等函数进行内存的动态分配、释放和调整大小。最后,探讨了C++中的new和delete运算符,以及如何通过自由存储列表管理内存。

weixin_36078669的博客 412

C与C++---指针、引用、结构体及内存管理

这是C++引入“引用”后最经典的对比。总的来说,引用是变量的“别名”,而指针是存储变量地址的“变量”。

会分享一些自己学习过程中的笔记,欢迎一起交流讨论 943

C++代码的常见性能瓶颈,C++如何通过优化算法、数据结构内存管理来提升性能。

通过识别和优化常见的性能瓶颈,使用合适的算法和数据结构,以及优化内存管理和I/O操作,C++程序的性能可以得到显著提升。

不会编程的码农研究僧 1474

C++内存管理之一】内存结构简介

文章目录一、内存结构简介1、内存分配方式1、栈2、堆3、自由存储去4、全局区(静态区)5、常量区2、堆栈的区别1、举个栗子2、区别 一、内存结构简介 C++的内存结构,主要分为五个区域: 栈区、堆区、全局区(静态区)、常量区、代码区。 扩展链接 堆栈大小设置 1、内存分配方式 1、栈 1、由编译器和操作系统管理; 2、函数执行开始时,函数内的局部变量存储在栈中;函数执行结束时,这些存储单元自动被释...

Joker_N的博客 4496

C++基础函数、内存管理结构体对象按照对象某个成员进行排序

// ConsoleApplicationC++jichu4.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "iostream" using namespace std; struct Date { int year; int month; int day; void print(){ cout << year << ' ' <&

baidu_19552787的博客 202

47、C/C++编程中的内存管理、循环优化与结构使用技巧

本文深入探讨了C/C++编程中的内存管理、循环优化和结构使用技巧。通过分析Oracle RDBMS的内存操作和Boehm GC垃圾回收机制,展示了如何高效管理内存并减少内存泄漏。文章还介绍了两种循环优化方式,适用于旧CPU和全局数组处理,并详细解析了结构的灵活使用技巧,如结构代替数组、未指定大小数组、结构版本控制以及原始序列化方法。通过实际示例和应用场景分析,帮助开发者提升代码性能和效率,适用于大型软件分析、嵌入式系统、数据处理、软件升级和数据存储等多个领域。

tree的博客 118

深入理解二叉树与内存管理C++数据结构实践

本文深入探讨了C++中二叉树的实现细节,包括节点的添加、删除、遍历以及内存管理。通过实例代码和详细的解释,阐述了如何在二叉搜索树中插入节点,并通过递归与非递归方式实现树的遍历。同时,文章也关注了内存分配与释放的过程,以及如何优化这些操作。

weixin_36178216的博客 381
上一篇: (初学)理解ICaptureGraphBuilder2 和 IGraphBuilde
下一篇: 用WORD2007写CSDN的BLOG
ding_net
博客等级 码龄25年 40粉丝 45原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值