C++内存管理详解:
内存分配方式简介
在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。
堆和栈究竟有什么区别?
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456 在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456 放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
二、Python
Python是用C实现的。
在python世界中,一切都是对象。整数、字符串、类型(如字符串类型)等都是对象。面向对象理论中的“类”“对象”在python中都是通过python内的对象实现的。
在python中,对象就是:为C 中的结构体在堆上申请的一块内存。
所有的内建的类型对象(如整数类型对象、字符串类型对象)都是被静态初始化的。
在python中,一个对象一旦被创建,它在内存中的大小就是不变的(而java在堆new的对象是在运行时动态分配内存的)。如果要容纳可变长度数据的对象,只能在对象内维护一个指向一块可变大小的内存区域。
和java、c#一样,python提供了对内存的垃圾收集(GC)机制。
python中所有的内存管理机制都有两套实现。这两套实现由编译符号PYMALLOC_DEBUG控制。
当该符号被定义时,使用debug模式下的内存管理机制。这套机制在正常的内存管理动作之外,还会记录许多关于内存的信息,以方便python在开发时进行调试。
当该符号未被定义时,python的内存管理机制只进行正常的内存管理动作。
python解释器中也开辟了堆栈,栈是用于存放指令集的,而堆是存放变量的
三、Java把内存划分为4个部分 :
1、栈区(stacksegment)—由编译器自动分配释放,存放函数的参数值,局部变量的值等,具体方法执行结束之后,系统自动释放JVM内存资源。
2、堆区(heapsegment)—一般由程序员分配释放,存放由new创建的对象和数组,jvm不定时查看这个对象,如果没有引用指向这个对象就回收。
3、静态区(datasegment)—存放全局变量,静态变量和字符串常量,不释放
4、代码区(codesegment)—存放程序中方法的二进制代码,而且是多个对象共享一个代码空间区域。
Java自动管理栈和堆,程序员不能直接地设置栈或堆。
当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。
要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。
java的内存管理机制
1、内存区域的分类
栈内存:基本类型变量和对象的引用,优势在于存取速度快
堆内存:new创建的对象和数组以及对象的实例化变量,优势在于动态分配内存,但是存取速度相对较慢
2、不同类型的内存分配
(1)基本数据类型:类似int,char,double之类的数据类型
当使用int a;来定义的时候,会在栈空间分配一个空间来存a(此时为空);当使用int a=2;来定义的时候,会在栈空间分配一个空间来存a,同时去找有没有值为2的内存空间,如果有就把a的地址空间指向2的地址空间,如果没有就创建值为2的地址空间,把a的地址空间指向那个地址空间。
(2)对象
对对象的内存分配主要是在栈空间存放对象的地址(对应的堆空间的地址),在堆空间存放对象
(3)String
String其实就是一个类,但是有比较特殊的地方。
String s = new String(“Hello,World!”); 和 String s = “Hello,World!”; 是不一样的:
前者和普通类是一样的,后者与基本类型类似,会先去找有没有”Hello,World!”,如果没有才会去创建一个值为”Hello,World!”的对象,然后栈空间存放这个对象的在堆中的地址(记这个栈空间的地址为X,X不是对象在堆中的地址),s在栈空间的值是X。
(4)数组
栈中存放数组在堆中的首地址,堆中分配数组。
(5)方法调用时的内存分配
实例变量和对象在堆中,局部变量在栈中(方法执行完成之后就会被回收)
3、垃圾回收机制
(1)方式
JVM自己回收或者是system.gc();请求回收。
(2)对象
1)空引用:String s = null;此时s就会被回收
2)没有引用:String s = “a”;s = “b”;那么a就变成“无主孤魂”就会被回收
3)过期:方法运行完成后,方法中的局部变量就会被回收
4)互相引用:对象A引用了对象B,B直接或者间接引用了对象A,而且A和B都不被其他对象所引用,这样也会被回收
(3)垃圾回收算法
http://speed847.iteye.com/blog/373278
内存分配策略
静态存储分配
是指在编译时期就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间
静态分配策略要求程序代码中不许有可变数据结构的存在,也不允许有嵌套或者递归的结构出现(因为会导致编译程序无法计算准确的存储空间)
栈式存储分配
也称动态存储分配,是由一个类似于堆栈的运行栈来实现的,和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存。
堆式存储分配
专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配
比如可变长字符串和对象实例
堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放
————————————————
https://www.cnblogs.com/Berryxiong/p/6217442.html
https://www.cnblogs.com/butterfly100/p/9175673.html