{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/cpp-memory-model/",
  "atlas": "https://www.pystone.net/?node=cpp-memory-model#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/cpp-memory-model.md",
  "context": "https://www.pystone.net/notes/cpp-memory-model.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:cpp-memory-model",
  "slug": "cpp-memory-model",
  "title": "内存模型",
  "type": "note",
  "visibility": "public",
  "idStability": "rename-stable",
  "author": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "publisher": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "aliases": [],
  "summary": "内存模型",
  "contentRole": "unspecified",
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "unspecified",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "contentHash": "9f2baa70a3f6eed8b2770d61c302f5083993bdb6efbc288641275490378a199a",
  "assets": [
    {
      "reference": "assets/0009 - 内存模型__resource-001-ff6393a054f1.png",
      "url": "/media/5f75f9332608bd8d937d.png",
      "mediaType": "image/png",
      "contentHash": "5f75f9332608bd8d937de1a36ae380eebdf356b4eb9f084db7ec8e8ff9b878cf",
      "byteLength": 31169,
      "width": 706,
      "height": 591
    }
  ],
  "headings": [
    {
      "depth": 1,
      "text": "内存模型",
      "anchor": "内存模型",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B"
    },
    {
      "depth": 2,
      "text": "内存占用",
      "anchor": "内存占用",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E5%86%85%E5%AD%98%E5%8D%A0%E7%94%A8"
    },
    {
      "depth": 2,
      "text": "三种内存分配方式",
      "anchor": "三种内存分配方式",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E4%B8%89%E7%A7%8D%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E6%96%B9%E5%BC%8F"
    },
    {
      "depth": 4,
      "text": "从静态存储区分配",
      "anchor": "从静态存储区分配",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E4%BB%8E%E9%9D%99%E6%80%81%E5%AD%98%E5%82%A8%E5%8C%BA%E5%88%86%E9%85%8D"
    },
    {
      "depth": 4,
      "text": "在栈上创建",
      "anchor": "在栈上创建",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E5%9C%A8%E6%A0%88%E4%B8%8A%E5%88%9B%E5%BB%BA"
    },
    {
      "depth": 4,
      "text": "从堆上分配（动态内存分配）",
      "anchor": "从堆上分配动态内存分配",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E4%BB%8E%E5%A0%86%E4%B8%8A%E5%88%86%E9%85%8D%E5%8A%A8%E6%80%81%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D"
    },
    {
      "depth": 2,
      "text": "关于堆区和栈区",
      "anchor": "关于堆区和栈区",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E5%85%B3%E4%BA%8E%E5%A0%86%E5%8C%BA%E5%92%8C%E6%A0%88%E5%8C%BA"
    },
    {
      "depth": 3,
      "text": "堆和栈的区别",
      "anchor": "堆和栈的区别",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E5%A0%86%E5%92%8C%E6%A0%88%E7%9A%84%E5%8C%BA%E5%88%AB"
    },
    {
      "depth": 2,
      "text": "内存对齐（memory alignment）",
      "anchor": "内存对齐memory-alignment",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90memory-alignment"
    },
    {
      "depth": 2,
      "text": "内存的使用简介",
      "anchor": "内存的使用简介",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E5%86%85%E5%AD%98%E7%9A%84%E4%BD%BF%E7%94%A8%E7%AE%80%E4%BB%8B"
    },
    {
      "depth": 2,
      "text": "函数调用的过程——函数栈",
      "anchor": "函数调用的过程函数栈",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8%E7%9A%84%E8%BF%87%E7%A8%8B%E5%87%BD%E6%95%B0%E6%A0%88"
    },
    {
      "depth": 2,
      "text": "经典的堆栈的讲解",
      "anchor": "经典的堆栈的讲解",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E7%BB%8F%E5%85%B8%E7%9A%84%E5%A0%86%E6%A0%88%E7%9A%84%E8%AE%B2%E8%A7%A3"
    },
    {
      "depth": 2,
      "text": "new和malloc的区别",
      "anchor": "new和malloc的区别",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#new%E5%92%8Cmalloc%E7%9A%84%E5%8C%BA%E5%88%AB"
    },
    {
      "depth": 2,
      "text": "具体的内存分配问题",
      "anchor": "具体的内存分配问题",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#%E5%85%B7%E4%BD%93%E7%9A%84%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E9%97%AE%E9%A2%98"
    },
    {
      "depth": 2,
      "text": "Ref",
      "anchor": "ref",
      "citation": "https://www.pystone.net/notes/cpp-memory-model/#ref"
    }
  ],
  "claims": [],
  "outgoing": [],
  "incoming": [
    {
      "id": "note:programming-languages-and-runtimes",
      "title": "编程语言与运行时",
      "url": "https://www.pystone.net/notes/programming-languages-and-runtimes/",
      "atlas": "https://www.pystone.net/?node=programming-languages-and-runtimes#knowledge-atlas",
      "label": "编程语言与运行时",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "C++中的“内存模型”导航项",
      "citation": "https://www.pystone.net/notes/programming-languages-and-runtimes/#c"
    }
  ],
  "contentMarkdown": "# 内存模型\n\n﻿# 内存模型\n\n> 创建时间：2020/3/10 12:51\n\n* 内存占用\n  * 三种内存分配方式\n    * 从静态存储区分配\n    * 在栈上创建\n    * 从堆上分配（动态内存分配）\n  * 关于堆区和栈区\n    * 堆和栈的区别\n  * 内存对齐（memory alignment）\n  * 内存的使用简介\n  * 函数调用的过程——函数栈\n  * 经典的堆栈的讲解\n  * new和malloc的区别\n  * 具体的内存分配问题\n  * Ref\n\n## 内存占用\n\n栈区（stack）：由编译器自动分配与释放，存放为运行时函数分配的局部变量、函数参数、返回数据、返回地址等。其操作类似于数据结构中的栈。\n堆区（heap）：一般由程序员自动分配，如果程序员没有释放，程序结束时可能有OS回收。其分配类似于链表。\n全局/静态存储区 （static .bss段和.data段）：存放全局变量、静态数据、常量。程序结束后由系统释放。全局区分为已初始化全局区（data）和未初始化全局区（bss）。\n常量区（.rodata段）：存放常量字符串，程序结束后有系统释放。\n代码区（.text段）：存放函数体（类成员函数和全局区）的二进制代码。\n\n## 三种内存分配方式\n\n#### 从静态存储区分配\n\n内存在程序编译的时候已经分配好，这块内存在程序的整个运行期间都存在。例如全局变量，static变量。\n\n#### 在栈上创建\n\n在执行函数时，函数内局部变量的存储单元可以在栈上创建，函数执行结束时，这些内存单元会自动被释放。\n栈内存分配运算内置于处理器的指令集，效率高，但是分配的内存容量有限。\n\n#### 从堆上分配（动态内存分配）\n\n程序在运行的时候使用malloc或者new申请任意多少的内存，程序员自己负责在何时用free或delete释放内存。\n动态内存的生命周期有程序员决定，使用非常灵活，但如果在堆上分配了空间，既有责任回收它，否则运行的程序会出现内存泄漏，频繁的分配和释放不同大小的堆空间将会产生内存碎片。\n\n![](assets/0009 - 内存模型__resource-001-ff6393a054f1.png)\n\n## 关于堆区和栈区\n\n栈区（stack）用于存放局部变量、返回地址、函数的实参等，由编译器自动分配释放。栈的功能主要是函数调用、局部变量申请、函数参数传递所使用的空间，是为函数调用的实现提供一些保存、恢复操作。一般情况下栈空间都特别小。\n在windows下，栈地址是向低地址扩展的数据结构，是一块连续的内存区域。栈顶的地址和栈的最大容量是系统预先规定好的，在windows下，栈的大小是2MB，而申请堆空间的大小一般小于2GB\n栈存放的数据占空间比较小，而且栈内存不由程序员来管理，存放在栈里面的局部变量随着函数调用结束就自动释放了。\n\n堆区（heap）是一个程序运行动态分配的内存区域。一般由程序员分配释放，若程序员不释放，程序结束时可能由OS回收。 程序员通过new等方式创建的对象，一般会在堆区中分配内存。\n\n我们平常说的GC，指的是对堆内存的回收。对内存的优化一般也指的是堆内存。\n\n### 堆和栈的区别\n\n**管理方式** 不同： **栈** 是由 **编译器自动** 申请和释放空间， **堆** 是需要 **程序员手动** 申请和释放；\n**空间** 大小不同： **栈** 的空间是有限的，在32位平台下，VC6下默认为 **1M** ， **堆** 最大可以到 **4G** ；\n能否产生 **碎片** ： **栈** 和数据结构中的栈原理相同，在弹出一个元素之前，上一个已经弹出了， **不会** 产生碎片，如果不停地调用 **malloc、free堆** 造成内存 **碎片很多** ；\n**生长方向** 不同： **堆** 生长方向是 **向上** 的，也就是向着内存地址增加的方向， **栈** 刚好相反，向着内存 **减小的方向** 生长。\n**分配方式** 不同： **堆** 都是 **动态分配** 的，没有静态分配的堆。 **栈** 有 **静态** 分配和 **动态** 分配。 **静态** 分配是 **编译器完成** 的，比如局部变量的分配。 **动态分配** 由 **malloc 函数进行分配** ，但是栈的动态分配和堆是不同的，它的 **动态分配是由编译器进行释放** ，无需我们手工实现。\n**分配效率** 不同： **栈** 的效率比堆 **高** 很多。栈是机器系统提供的数据结构，计算机在底层提供栈的支持，分配专门的寄存器来存放栈的地址，压栈出栈都有相应的指令，因此比较快。 **堆** 是由库函数提供的，机制很复杂，库函数会按照一定的算法进行搜索内存，因此比较慢。\n\n栈区（stack）用于存放局部变量、返回地址、函数的实参等，由编译器自动分配释放。栈的功能主要是函数调用、局部变量申请、函数参数传递所使用的空间，是为函数调用的实现提供一些保存、恢复操作。一般情况下栈空间都特别小。\n在windows下，栈地址是向低地址扩展的数据结构，是一块连续的内存区域。栈顶的地址和栈的最大容量是系统预先规定好的，在windows下，栈的大小是2MB，而申请堆空间的大小一般小于2GB\n栈存放的数据占空间比较小，而且栈内存不由程序员来管理，存放在栈里面的局部变量随着函数调用结束就自动释放了。\n\n栈区大小的限制，不同的资料上有不同的说法，有个文章说申请大小的限制是1或者2M，可以自己改，但是最大不超过8M\n\n堆区（heap）是一个程序运行动态分配的内存区域。一般由程序员分配释放，若程序员不释放，程序结束时可能由OS回收。 程序员通过new等方式创建的对象，一般会在堆区中分配内存。\n\n我们平常说的GC，指的是对堆内存的回收。对内存的优化一般也指的是堆内存。\n\n嗯，这段描述基本适用于多数语言了。不过c# 函数里new的struct对象（值类型）一般情况都是在栈上的，和c++不一样。然后堆的空间在64位下就没有2G或者4G的限制了。\n\n## 内存对齐（memory alignment）\n\n操作的内存地址（更准确的说，操作内存的起始地址）能够被操作的内存大小整除，满足这个要求的内存访问叫做访问对齐的内存（aligned memory access），否则就是访问未对齐的内存（unaligned memory access）。\nhttps://www.cnblogs.com/zhao-zongsheng/p/9099603.html\n\n## 内存的使用简介\n\n在Windows平台下，高级语言写出的程序经过编译链接，最终会变成PE文件。当PE文件被装载运行后，就成了所谓的进程。\nPE文件代码段中包含的二进制级别的机器代码会被装入内存的 **代码区(.text)** ，处理器将到内存的这个区域一条一条地取出指令和操作数，并送入运算逻辑单元进行运算；如果代码中请求开辟 **动态内存** ，则会在内存的 **堆区** 分配一块大小合适的区域返回给代码区的代码使用；当函数调用发生时， **函数的调用关系等信息** 会动态地保存在内存的 **栈区** ，以供处理器在执行完被调用函数的代码时，返回母函数。\n\n## 函数调用的过程——函数栈\n\nhttps://blog.csdn.net/m0_37717595/article/details/80368411\n\n## 经典的堆栈的讲解\n\nhttps://blog.csdn.net/yingms/article/details/53188974\n\n## new和malloc的区别\n\n  1. new 是 **运算符** malloc是 **库函数**\n  2. **new和delete底层还是由malloc和free实现** 的，区别在于new和delete在生成复杂数据类型时会执行两步: **分配内存** 和 **调用构造函数** / **调用析构函数** 和 **销毁内存** 。\n  3. **malloc** 申请的内存 **没有类型** ,为(void*) 需要根据使用需求进行强制转换, **new** 不需要,返回 **对应类型的指针** 。\n  4. new并不是每次都会调用构造函数，对于简单类型eg.int是不需要的。\n\n## 具体的内存分配问题\n\n局部变量存在栈区，malloc()分配的空间在堆区。\nmalloc使用堆空间。\nmalloc 申请空间，需要标注大小，free释放的是指针指向的空间\n\n>   * 当不需要再使用申请的内存时，记得 **释放** ，并 **且指针=NULL** ；释放后应该把指向这块内存的指针指向NULL， **防止程序后面不小心使用了它** 。\n>   * free时候,指针不能发生偏移，原因是指针指向的是申请空间的首地址，而且申请的空间的大小在free源码结构体中有记录\n>\n\n例子：\n\n```cpp\nstring str1 = &quot;test&quot;;\nstring str2 = &quot;test&quot;;\n\n```\n\n## Ref\n\nhttps://www.cnblogs.com/houjun/p/4909413.html\nhttps://www.cnblogs.com/qiuly/p/8576149.html\nhttp://www.360doc.com/content/12/0102/11/1299815_176623363.shtml\nhttps://www.zhihu.com/question/19729973\nhttp://www.360doc.com/content/12/0102/11/1299815_176623363.shtml\nhttps://blog.csdn.net/yingms/article/details/53188974\nhttps://www.cnblogs.com/cchHers/p/10010275.html\nhttps://zhuanlan.zhihu.com/p/78478567\nhttps://www.zhihu.com/question/59238963\nhttps://blog.csdn.net/cherrydreamsover/article/details/81627855\nhttps://blog.csdn.net/buptzy/article/details/80149622\nhttps://www.cnblogs.com/will-boot/p/3302936.html\n"
}
