程序在运行时都要开辟空间,任何软件在运行时都要在内存中开辟空间;
虚拟机运行时也是要开辟空间的。
JVM(虚拟机)运行时在内存中开辟一片内存区域,启动时在自己的内存区域中进行更细致的划分,
因为虚拟机中每一片内存处理的方式都不同,所以要单独进行管理。
我们重点来说一下堆和栈:
栈内存:
栈内存首先是一片内存区域,存储的都是局部变量(那就是说局部变量都是存在栈中)
凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,
是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。
栈内存的更新速度很快,因为局部变量的生命周期都很短。
堆内存:
存储的是数组和对象(其实数组就是对象)(那也就是说,数组和对象都是在堆中),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),
如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,
但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。
堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。
所以堆与栈的区别很明显:
1.栈内存 存储的是局部变量而堆内存存储的是实体;
2.栈内存的更新速度>堆内存,因为局部变量的生命周期很短;
3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。
栈 栈的特性:先进后出,主要为一个线程独享,为这个线程的函数的调用服务的。 用于存放返回地址,零时变量个参数而用。 栈的内存一般都是由编译器自己来分配释放的,编译器所分配的内存是连续的,当定义一个变量的时候,在当前栈区的尾部来分配新的变量的内存。 在windows系统里面栈的大小是2M, 在linux系统里面栈的大小是8M, 可以使用ulimit-s来设置栈的大小。 栈的空间的分配是由高地址向低地址分配的。 堆 堆的分配和释放是由程序员来分配和释放。 在windows系统里面一般是小于2G的。 因为系统是用链表来实现空闲地址空间的,所以堆的内存空间不是连续的, 链表的遍历也是由低地址到高地址的,所以分配内存也是又低地址向高地址分配。 申请后系统的响应 栈:只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则将报异常提示栈溢出。 堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,
然后将该节点从空闲结点链表中删除,并将该结点的空间分配给程序。对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete语句才能正确的释放本内存空间。
另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动地将对于的那部分重新放入空闲的链表中。 栈和堆中存储的内容 栈:在函数调用时,第一个进栈的是主函数中的下一条指令的地址,然后是函数的各个参数,在大多数C编译器中,参数是由右向左入栈的,然后是函数中的局部变量,注意静态变量是不入栈的,静态变量存储在静态存储区。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。 堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。 申请效率 栈:由系统自己分配,速度较快,但是程序员无法掌握。 堆:一般有两种方法来申请内存,new、和malloc,new是一种用算符而malloc是函数。由程序员申请出来的内存一般速度比较慢,而却容易产生内存碎片,不过用起来比较方便。 特点 堆的大小取决于操作系统有效的虚拟内存的大小,堆获得空间比较灵活,也相对而言比较大,但是速度慢;栈的话分配内存就相对快很多了。