分享

Java面试相关——堆和栈-简书

 Frank_Chia 2018-01-10

引言:Java 中的堆和栈 Java把内存划分成两种:一种是栈内存,一种是堆内存。至于“方法区”(静态存储区),可以理解为:主要存放静态数据、全局 static 数据和常量。这块内存在程序编译时就已经分配好,并且在程序整个运行期间都存在。总的来说:堆和栈针对非静态数据,而方法区针对静态数据。

Java面试相关——堆和栈-简书

一、堆内存和栈内存

栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

·栈:

o简单理解:堆栈(stack)是操作系统在建立某个进程或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有先进后出的特性。

o特点:存取速度比堆要快,仅次于直接位于CPU中的寄存器。栈中的数据可以共享(意思是:栈中的数据可以被多个变量共同引用)。

o缺点:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

o相关存放对象:①一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄【例如:在函数中定义的一些基本类型的变量和对象的引用变量】。②方法的形参 直接在栈空间分配,当方法调用完成后从栈空间回收。

o特殊:①方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完成后从栈空间回收。②局部变量new出来之后,在栈控件和堆空间中分配空间,当局部变量生命周期结束后,它的栈空间立刻被回收,它的堆空间等待GC回收。

·堆:

o简单理解:每个Java应用都唯一对应一个JVM实例,每一个JVM实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或者数组都放在这个堆中,并由应用所有的线程共享。Java中分配堆内存是自动初始化的,Java中所有对象的存储控件都是在堆中分配的,但这些对象的引用则是在栈中分配,也就是一般在建立一个对象时,堆和栈都会分配内存。

o特点:可以动态地分配内存大小、比较灵活,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。

o缺点:由于要在运行时动态分配内存,存取速度较慢。

o主要存放:①由new创建的对象和数组 ;②this

o特殊:引用数据类型(需要用new来创建),既在栈控件分配一个地址空间,又在堆空间分配对象的类变量。

补充:在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。

引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。

引用变量是普通变量,定义时在栈中分配内存,引用变量在程序运行到作用域外释放。而数组&对象本身在堆中分配,即使程序运行到使用new产生数组和对象的语句所在地代码块之外,数组和对象本身占用的堆内存也不会被释放,数组和对象在没有引用变量指向它的时候,才变成垃圾,不能再被使用,但是仍然占着内存,在随后的一个不确定的时间被垃圾回收器释放掉。这个也是java比较占内存的主要原因

这里可以理解为:

String s1 = new String('abc');

这里面:'abc'表示栈中的一个存储空间中的一个数据,new String('abc')表示存在于堆中的一个对象,这个对象的值为‘abc’String s1则表示栈中定义的一个取了new String('abc')在堆中的首地址的一个特殊变量,也就是:s1成了引用变量,相当于一个别名。

二、Java数据存储和JVM内存分区

·JAVA中,有六个不同的地方可以存储数据:

1.寄存器(register。这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。但是寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。

2.堆栈(stack。位于通用RAM中,但通过它的“堆栈指针”可以从处理器哪里获得支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时候,JAVA编译器必须知道存储在堆栈内所有数据的确切大小和生命周期,因为它必须生成相应的代码,以便上下移动堆栈指针。这一约束限制了程序的灵活性,所以虽然某些Java数据存储在堆栈中——特别是对象引用,但是JAVA对象不存储其中。

3.堆(heap。一种通用性的内存池(也存在于RAM中),用于存放所以的JAVA对象。堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候

,只需要new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆进行存储分配比用堆栈进行存储存储需要更多的时间。

4.静态存储(static storage。这里的“静态”是指“在固定的位置”。静态存储里存放程序运行时一直存在的数据。你可用关键字static来标识一个对象的特定元素是静态的,但JAVA对象本身从来不会存放在静态存储空间里。

5.常量存储(constant storage。常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。有时,在嵌入式系统中,常量本身会和其他部分分割离开,所以在这种情况下,可以选择将其放在ROM中 。

6.RAM存储。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。

就速度来说,有如下关系:

寄存器 < 堆栈="">< 堆=""><>

Java面试相关——堆和栈-简书

·JVM的内存分区:

JVM的分区可分为三个:堆(heap)、栈(stack)和方法区(method)

1.堆区:

o存储的全是对象,每个对象都包含一个与之对应的class信息(我们常说的类类型,Clazz.getClass()等方式获取),class目的是得到操作指令。

oJVM只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身。【这里的‘对象’,就不包括基本数据类型】

4.栈区:

o每个线程包含自己的一个栈区,栈中只保存基本数据类型的对象和自定义对象的引用。

o每个栈中的数据(基本类型和对象引用)都是私有的,其他栈不可访问。

o栈 = 基本类型变量区 + 执行环境上下文 + 操作指令区(存放操作指令)

8.方法区【这个可能比较陌生】

o又称为‘静态区’,和堆一样,被所有的线程共享。

o方法区包含所有的class和static变量。

补充:大家也许听说过“数据区”或者“运行时数据区”这个名词,这里,我们说JVM是驱动Java程序运行的基础,而它有三个分区:堆、栈、方法区,实际上,JVM的三个方法区就是包含于 JVM的运行时数据区中的三大块。于是,“数据区”与上述的分区的关系就明朗了。

三、Java的两种数据类型:

1.基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,

并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。【自动变量存的是字面值,不是类的实例(即不是类的引用),这里并没有类的存在,如int a=3;
这里a只是指向int类型(不是类)的引用,指向字面值3,此时,由于这些字面值的数据大小可知并且生存期可知(他们在程序内某个固定代码块中,代码块退出,他们就消失),为了追求速度,于是存在中】

2.包装类,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于中,Java用new()语句来显式地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。

视频资料链接:

data:text/html;charset=UTF-8;base64,

5oGt5Zac5L2g77yM5p625p6E5biI5a2m5Lmg576k5Y+35pivNTc1NzUxODU0Cg==

复制粘贴在网站打开即可

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多