Java中堆与栈的内存分配-2019年文档

Java中堆与栈的内存分配

文献标识码:A

1 栈内存与堆内存概述

在函数中定义的基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码中定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。

堆内存用来存放由new创建的对象和数组,在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。在堆中产生一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用new产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器释放掉。

2 Java中内存分配策略

程序运行时,内存的分配有三种策略,分别是静态的、栈式的和堆式的。

静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给其分配固定的内存空间。这种分配策略要求程序代码中不允许有可变数据结构的存在,也不允许有嵌套或者递归的结构出现,因为会导致编译程序无法计算准确的存储空间需求。

栈式存储分配也称为动态存储分配,是由一个类似于堆栈的运行栈来实现的,和静态存储分配相反。在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道。但是规定在运行中进入一个程序模块时,必须知道程序模块所需的数据区大小才能够为其分配内存。栈式存储分配按照先进后出的原则进行分配。

堆式存储分配专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例。堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放。而静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求。 3 堆和栈的比较

从堆和栈的功能和作用来看,堆主要用来存放对象的,栈主

要是用来执行程序的。在程序设计中,所有的方法调用都是通过栈进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。退出函数的时候,修改栈指针就可以把栈中的内容销毁。该模式速度最快,而且在编译的时候就已经为一个即将要调用的程序模块设置好数据区的大小,运行时再分配下去。

堆是应用程序在运行的时候请求操作系统分配给自己内存,由于是操作系统管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率非常低。但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长时间。因此,用堆保存数据时会得到更大的灵活性。在面向对象的多态性中,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定。 4 JVM中的堆和栈

JVM是基于堆栈的虚拟机,JVM为每个新创建的线程都分配一个堆栈,即对于一个Java程序来说,它的运行是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态,JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。

某个线程正在执行的方法称为此线程的当前方法。当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的Java堆栈里新压入一个帧,成为当前帧。在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据。 每一个Java应用都唯一对应一个JVM实例,每一个实例唯一

联系客服:779662525#qq.com(#替换为@) 苏ICP备20003344号-4