内存管理

C

在C语言中,内存主要分为如下5个存储区:

  1. 栈(Stack):位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效。
  2. 堆(Heap):由程序员用malloc/calloc/realloc分配,free释放。如果程序员忘记free了,则会造成内存泄露,程序结束时该片内存会由OS回收。
  3. 全局区/静态区(Global Static Area): 全局变量和静态变量存放区,程序一经编译好,该区域便存在。并且在C语言中初始化的全局变量和静态变量和未初始化的放在相邻的两个区域(在C++中,由于全局变量和静态变量编译器会给这些变量自动初始化赋值,所以没有区分了)。由于全局变量一直占据内存空间且不易维护,推荐少用。程序结束时释放。
  4. C风格字符串常量存储区: 专门存放字符串常量的地方,程序结束时释放。
  5. 程序代码区:存放程序二进制代码的区域。

简单来说, c 并没有内存管理,完全是靠程序员手动释放和申请的.

C++

在C++语言中,与C类似,不过也有所不同,内存主要分为如下5个存储区:

  1. 栈(Stack):位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效。
  2. 堆(Heap):这里与C不同的是,该堆是由new申请的内存,由delete或delete[]负责释放
  3. 自由存储区(Free Storage):由程序员用malloc/calloc/realloc分配,free释放。如果程序员忘记free了,则会造成内存泄露,程序结束时该片内存会由OS回收。
  4. 全局区/静态区(Global Static Area): 全局变量和静态变量存放区,程序一经编译好,该区域便存在。在C++中,由于全局变量和静态变量编译器会给这些变量自动初始化赋值,所以没有区分了初始化变量和未初始化变量了。由于全局变量一直占据内存空间且不易维护,推荐少用。程序结束时释放。
  5. 常量存储区: 这是一块比较特殊的存储区,专门存储不能修改的常量(如果采用非正常手段更改当然也是可以的了)。

C++为了能兼容 C,对内存机制也是一个悲剧~

Java

 对于Java程序员来说,在虚拟机的自动内存管理机制的帮助下,不再需要为每一个new操作去写配对的delete/free代码,而且不容易出现内存泄漏和内存溢出问题,看起来由虚拟机管理内存一切都很美好。不过,也正是因为Java程序员把内存控制的权力交给了Java虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那排查错误将会成为一项异常艰难的工作。  

java 的内存管理:

  1. 程序运行前:JVM向操作系统请求一定的内存空间,称为初始内存空间!程序执行过程中所需的内存都是由java虚拟机从这片内存空间中划分的。
  2. 程序运行中:java程序一直向java虚拟机申请内存,当程序所需要的内存空间超出初始内存空间时,java虚拟机会再次向操作系统申请更多的内存供程序使用!
  3. 内存溢出:程序接着运行,当java虚拟机已申请的内存达到了规定的最大内存空间,但程序还需要更多的内存,这时会出现内存溢出的错误!

内存空间逻辑划分:

  1. 方法区:方法区默认最大容量为64M,Java虚拟机会将加载的java类存入方法区,保存类的结构(属性与方法),类静态成员等内容。
  2. 堆:默认最大容量为64M,堆存放对象持有的数据,同时保持对原类的引用。可以简单的理解为对象属性的值保存在堆中,对象调用的方法保存在方法区。
  3. 栈:栈默认最大容量为1M,在程序运行时,每当遇到方法调用时,Java虚拟机就会在栈中划分一块内存称为栈帧(Stack frame),栈帧中的内存供局部变量(包括基本类型与引用类型)使用,当方法调用结束后,Java虚拟机会收回此栈帧占用的内存。

java的内存管理使用的是垃圾回收机制,具体的垃圾回收策略可以 google 一下,它有一系列变化,展开又是一片博文了.

python

Python的内存管理机制可以从三个方面来讲:

  • 引用计数
  • 垃圾回收
  • 内存池机制

1 引用计数

Python采用了类似Windows内核对象一样的方式来对内存进行管理。每一个对象,都维护这一个对指向该对对象的引用的计数。

例如:

x = 3.14

y = x

这里的'引用'其实和 c 中的指针意义相近,如果理解 c 指针,那么就不难理解 python 的引用机制.这里的 x和 y 其实指向的是同一个对象3.14.

2 垃圾回收

python不像C++,Java等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值。对Python语言来讲,对象的类型和内存都是在运行时确定的。这也是为什么我们称Python语言为动态类型的原因(这里我们把动态类型可以简单的归结为对变量内存地址的分配是在运行时自动判断变量类型并对变量进行赋值)。

3 内存池机制

Python的内存机制以金字塔行,-1,-2层主要有操作系统进行操作,

  • 第0层是C中的malloc,free等内存分配和释放函数进行操作;
  • 第1层和第2层是内存池,有Python的接口函数PyMem_Malloc函数实现,当对象小于256K时有该层直接分配内存;
  • 第3层是最上层,也就是我们对Python对象的直接操作;

在 C 中如果频繁的调用 malloc 与 free 时,是会产生性能问题的.再加上频繁的分配与释放小块的内存会产生内存碎片. Python 在这里主要干的工作有:

  • 如果请求分配的内存在1~256字节之间就使用自己的内存管理系统,否则直接使用 malloc.
  • 这里还是会调用 malloc 分配内存,但每次会分配一块大小为256k的大块内存.

  经由内存池登记的内存到最后还是会回收到内存池,并不会调用 C 的 free 释放掉.以便下次使用.对于简单的Python对象,例如数值、字符串,元组(tuple不允许被更改)采用的是复制的方式(深拷贝?),也就是说当将另一个变量B赋值给变量A时,虽然A和B的内存空间仍然相同,但当A的值发生变化时,会重新给A分配空间,A和B的地址变得不再相同