JAVA中堆和栈的区别和联系
一、Java的堆内存和栈内存
Java把内存划分成两种:一种是堆内存,一种是栈内存。
堆:主要用于储存实例化的对象,数组。由JVM动态分配内存空间。一个JVM只有一个堆内存,线程是可以共享数据的。
栈:主要用于储存局部变量和对象的引用变量,每个线程都会有一个独立的栈空间,所以线程之间是不共享数据的。
堆内存:储存的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。
栈内存:栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期很短。
二、Java中变量在内存中的分配
- 类变量(static修饰的变量):在程序加载时系统就为它在堆中开辟了内存,堆中的内存地址存放于栈以便于高速访问。静态变量的生命周期------一直持续到整个“系统”关闭
- 实例变量:当你使用java关键字new的时候,系统在堆中开辟并不一定是联系的空间分配给变量(比如说类实例),然后根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的“物理位置”。实例变量的生命周期-------当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放对中内存
- 局部变量:局部变量,由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一旦脱离作用域,内存立即释放
三、Java中变量的作用域
在Java中,变量的作用域分为四个级别:类级、对象实例级、方法级、块级
- 类级变量:又称全局变量或静态变量,需要使用static关键字修饰,你可以与C/C++中的static变量对比学习。类级变量在类定义后就已经存在,占用内存空间,可以通过类名来访问,不需要实例化。
- 对象实例级变量:又称成员变量,实例化后才会分配内存空间,才能访问。
- 方法级变量:就是在方法内部定义的变量,就是局部变量。
- 块级变量:就是定义在一个块内部的变量,变量的生存周期就是这个块,出了这个块就消失了,比如if、for语句的块。
块是指由大括号包围的代码,例如
{int age = 3;String name = "www.weixueyuan.net";// 正确,在块内部可以访问 age 和 name 变量System.out.println( name + "已经" + age + "岁了");
}
// 错误,在块外部无法访问 age 和 name 变量
System.out.println( name + "已经" + age + "岁了")
说明:
- 方法内部除了能访问方法级的变量,还可以访问类级和实例级的变量。
- 块内部能够访问类级、实例级变量,如果块被包含在方法内部,它还可以访问方法级的变量。
- 方法级和块级的变量必须被显示地初始化,否则不能访问。
演示代码:
public class Demo{public static String name = "微学苑"; // 类级变量public int i; // 对象实例级变量// 属性块,在类初始化属性时候运行{int j = 2;// 块级变量}public void test1() {int j = 3; // 方法级变量if(j == 3) {int k = 5; // 块级变量}// 这里不能访问块级变量,块级变量只能在块内部访问System.out.println("name=" + name + ", i=" + i + ", j=" + j);}public static void main(String[] args) {// 不创建对象,直接通过类名访问类级变量System.out.println(Demo.name);// 创建对象并访问它的方法Demo t = new Demo();t.test1();}
}
运行结果:
微学苑
name=微学苑, i=0, j=3
下面我们通过一个图例详细讲一下堆和栈:
比如主函数里的语句 int[] arr = new int[3];在内存中是怎么被定义的:
主函数先进栈,在栈中定义一个变量arr,接下来为arr赋值,但是右边不是一个具体值,是一个实体。实体创建在堆里,在堆里首先通过new关键字开辟一个空间,内存在储存数据的时候都是通过地址来体现的,地址是一块连续的二进制,然后给这个实体分配一个内存地址。数组都是有一个索引,数组这个实体在堆内存中产生之后每一个空间都会进行默认的初始化(这是堆内存的特点,未初始化的数据是不能用的,但在堆里是可以用的,因为初始化过了,但是在栈里没有),不同的类型初始化的值不一样。所以堆和栈里就创建了变量和实体:
那么堆和栈是怎么联系起来的呢?
我们刚刚说过给堆分配一个地址,把堆的地址赋给arr,arr就通过地址指向了数组。所以arr想操纵数组时,就通过地址,而不是直接把实体赋给它。这种我们不再叫他基本数据类型,而叫引用数据类型。称为arr引用了堆内存当中的实体。(可以理解为c或c++的指针,Java成长自c++,和c++很像,优化了c++)
如果当int [] arr = null;
arr不做任何指向,null的作用就是取消引用数据类型的指向。
当一个实体,没有引用数据类型指向的时候,它在堆内存中不会被释放,而被当做一个垃圾,在不定时的时间内自动回收,因为Java有一个自动回收机制,(而c++没有,需要程序员手动回收,如果不回收就越堆越多,直到撑满内存溢出,所以Java在内存管理上优于c++)。自动回收机制(程序)自动检测堆里是否有垃圾,如果有,就会自动的做垃圾回收的动作,但是什么时候收不一定。
所以堆和栈的区别很明显:
- 栈内存存储的是局部变量而堆内存储存的是实体;
- 栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;
- 栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。
Java堆和栈的区别
- 各司其职
最主要的区别就是栈内存用来存储局部变量和方法调用。而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。
- 独有还是共享
栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。
- 异常错误
如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError。
而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError。
- 空间大小
栈的内存要远远小于堆内存,如果你使用递归的话,那么你的栈很快就会充满。如果递归没有及时跳出,很可能发生StackOverFlowError问题。
你可以通过-Xss选项设置栈内存的大小。-Xms选项可以设置堆的开始时的大小,-Xmx选项可以设置堆的最大值。
这就是Java中堆和栈的区别。理解好这个问题的话,可以对你解决开发中的问题,分析堆内存和栈内存使用,甚至性能调优都有帮助。
JAVA中堆和栈的区别和联系相关推荐
- java中堆和栈的区别!!!!
Java的堆是一个运行时数据区,类的(对象从中分配空间.这些对象通过new.newarray.anewarray和multianewarray等 指令建立,它们不需要程序代码来显式的释放.堆是由垃圾回 ...
- 让你彻底明白JAVA中堆与栈的区别
原文地址:http://www.2cto.com/kf/201302/190704.html 简单的说: Java把内存划分成两种:一种是栈内存,一种是堆内存. 在函数中定义的一些基本类型的变量和对象 ...
- java中堆与栈的区别_java中堆和栈的区别分析
堆和栈是Java数据结构里非常重要的概念,本文较为详细的分析了二者之间的区别.供大家参考.具体如下: Java的堆是一个运行时数据区,类的(对象从中分配空间.这些对象通过new.newarray.an ...
- [Java_kaikeba]java中堆和栈的区别(对象变量的理解)
.堆和栈都是java用来在RAM中存放数据的地方.与C++不同,java自动管理堆栈, 程序员不能直接设置堆栈. .区别 1. .栈中存放基本数据类型变量(int. ...
- JAVA中堆和栈的区别[面试常问点一]
概念 堆内存:在java虚拟jvm中堆内存主要是存储数组和对象(当然数组也是对象),只要是通过new关键字创建的对象都是在堆中,而堆中存放的就是对象的实体,实体用来封装数据的,封装对象的属性,所以堆内 ...
- 面试:说说Java 中堆和栈的区别?
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | nnngu 来源 | cnblogs.com/ ...
- JAVA中堆和栈的区别
堆:(对象) 引用类型的变量,其内存分配在堆上或者常量池(字符串常量.基本数据类型常量),需要通过new等方式来创建. 堆内存主要作用是存放运行时创建(new)的对象. (主要用于存放对象,存取速度慢 ...
- java中堆与栈的区别 彻底理解
每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆.应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有 的线程共享.跟C/C++不同,Java中分配堆内存是自动初始 ...
- Java虚拟机:Java中堆和栈的详细区别
一.Java中内存分配策略: 在比较堆和栈的区别之前,我们先了解下Java的内存分配策略,按照编译原理的观点,程序运行时的内存分配有三种策略,分别是:静态的,栈式的,和堆式的. (1)静态存储分配:是 ...
最新文章
- 2002年3月英伟达发布核弹GPU与大算力自动驾驶芯片
- C++——String类超详细介绍
- Python修改Mitsuba的XML相关参数
- 参加第一届宇宙 JavaScript 大会是怎样的体验
- P3797 妖梦斩木棒 线段树区间合并
- mysql分页取数每一页生成xml_让MyBatis Generator产生的代码支持分页
- python中类方法与实例方法的区别-python中类方法、类实例方法、静态方法的使用与区别...
- CentOS中怎样查看系统版本和内核版本
- Springboot注册Servlet
- 第二节 CSS入门介绍
- 学成在线--7.CMS页面管理开发(异常处理)
- Servlet梳理一
- 时间序列分析(2)| ARMA模型的(偏)自相关函数
- 关于java第八章的想法
- Ant-编译构建(2)-第3方jar包引入、log4j2
- godot读写本地文件
- CAD编辑指南5:输出高清图片和新建空白图纸
- 什么是localhost(127.0.0.1)?
- gan处理自己的数据集_使用StyleGAN训练自己的数据集.md
- L1-009 N个数求和 (20分) C语言