认识堆与栈

栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
Java的堆是一个运行时数据区,类的对象从中分配空间。这些对象通过new、newarray、anewarray和 multianewarray等指令建立,它们不需要程序代码来显式的释放。

堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。

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


栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。

但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。

栈有一个很重要的特殊性,就是存在栈中的数据可以共享。

举例分析

基本类型变量分析

假设我们同时定义:

int a = 3;
int b = 3;

编译器先处理int a = 3;

首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。

接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。

这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。

要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。

而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。(好好体会这两种共享,在堆和栈中的各自的区别)

引用类型变量分析

String是一个特殊的包装类数据。
可以用:

String str = new String("abc");
String str = "abc";

两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。

而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指 向”abc”,如果已经有”abc” 则直接令str指向“abc”。

对于String类,比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。

ps:这里涉及到equals()方法的源码,String类重写了equals()方法,相当于比较字符串的内容。没有重写的,都是==,比较的是引用的地址。

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true

可以看出str1和str2是指向同一个对象的。

String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false

用new的方式是生成不同的对象。每一次生成一个。
因此用第二种方式(String str1 ="abc")来创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。

而对于String str = new String("abc")的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。
另一方面, 要注意: 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。

小心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的 对象。只有通过new()方法才能保证每次都创建一个新的对象。
由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。

汇总

一、java中内存分配策略及堆和栈的比较
1、内存分配策略
a.按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的.
静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.

这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求.

b.栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.

和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知的栈一样, 栈式存储分配按照先进后出的原则进行分配。

c.静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,

而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放.

2、JVM中的堆和栈总结

Java堆:
1.程序运行中动态分配内存大小
2.java的垃圾回收器自动回收不再使用的数据
Java栈:
1.栈数据可以共享
2.存在栈中的数据大小与生存期必须是确定的。
3.栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象引用。

为什么会有栈内存和堆内存之分?

ps:上面的文字详细回答了创建的对象,存储的位置,生命周期。
 

(转)认识java中的堆和栈的更多相关文章

  1. java中的堆、栈、常量池

    java中的堆.栈.常量池 分类: java2010-01-15 03:03 4248人阅读 评论(5) 收藏 举报 javastring编译器jvm存储equals Java内存分配: 1. 寄存器 ...

  2. java中的堆与栈

    Java 中的堆和栈 Java把内存划分成两种:一种是栈内存,一种是堆内存. 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配 . 当在一段代码块定义一个变量时,Java就在栈中 ...

  3. 详细介绍Java中的堆、栈和常量池

    下面主要介绍JAVA中的堆.栈和常量池: 1.寄存器 最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈 存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在 ...

  4. Java中的堆和栈

    Java中的堆和栈 栈内存 存放基本数据类型和引用变量 堆内存 存放运行时创建的对象 一般来说,通过new关键字创建出来的对象都放在堆内存中 由于JVM是基于堆栈的虚拟机,而每个Java程序都运行在一 ...

  5. Java中的堆和栈的区别

    当一个人开始学习Java或者其他编程语言的时候,会接触到堆和栈,由于一开始没有明确清晰的说明解释,很多人会产生很多疑问,什么是堆,什么是栈,堆和栈有什么区别?更糟糕的是,Java中存在栈这样一个后进先 ...

  6. java中的堆、栈、常量池以及String类型的两种声明

    参考自http://blog.sina.com.cn/s/blog_798b04f90100ta67.html http://www.cnblogs.com/fguozhu/articles/2661 ...

  7. Java基础知识强化03:Java中的堆与栈

    1.在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认识Stack和Heap,并通过这些原理认清Java中静态方法和静态属性的问题. 一般,JV ...

  8. (转)举例讲解JAVA中的堆和栈

    转自:http://blog.csdn.net/lifuxiangcaohui/article/details/24936839 Java中堆和堆栈的区别 1. 栈(stack)与堆(heap)都是J ...

  9. java中的堆,栈和方法区(转)

    来源:https://www.cnblogs.com/iliuyuet/p/5603618.html https://blog.csdn.net/lin542405822/article/detail ...

随机推荐

  1. 利用SSH框架开发时遇到的各种Bug及解决方法

    .hibernate自动生成的配置文件 hibernate.cfg.xml 有时候是有问题的,会出现 org.hibernate.HibernateException: Could not parse ...

  2. 前端基于JQgrid实现自定义列头展示

    先上效果图   因为公司项目的需要,并且公司只有我这一个能写js的前端,这个自定义展示jqgrid列选项的需求依然是交由我写,辣么就分享一下我的工作成果. //初始化函数 multiSelectCol ...

  3. 通过数据,修改金蝶ERP的收料通知单不合格和合格数量,修改生产投料单,委外发出数量

    update POInStockEntry set FAuxNotPassQty=不合格数量 where FInterID=(select FInterID from POInStock where ...

  4. 关于CSS样式优先级学习心得

    1.未重复时候,只要有都有格式显示 2.重复时,看权值: 权值:标签 1 <类10< ID 100 PS:(*权值 > 继承(表格属性一般无法继承,有些浏览器也不支持表格继承父标签) ...

  5. “java.lang.IllegalArgumentException: Failed to evaluate expression ‘ROLE_USER’”报错的解决

    这个问题出现在Spring Security的相关配置中,找到原来的这一行: <security:intercept-url pattern="/**" access=&qu ...

  6. Navicat连接报错:cannot load OCI DLL,126

    32位系统下报错:cannot load OCI DLL,126 解决方法:navicat 菜单中 -工具->选项->OCI 选择oracle安装目录下bin里面的oci.dll 在win ...

  7. Qt开发陷阱一QSTACKWIDGET

    原始日期:2015-10-14 00:55 1.使用QStackWidget控件的setCurrentIndex方法时,要注意参数0对应着ui上StackWidget的page1,而不是page0,没 ...

  8. web移动端布局方式整理

    写H5页面一直写的有点随意,只是保证了页面在各个屏幕下显示良好,却没有保证到在各个屏幕下是等比例放大或者缩小.这些天在写一些页面,试着看看能不能写出等比例放大缩小的页面,发现不容易啊,在网上找了一些文 ...

  9. [leetcode-593-Valid Square]

    Given the coordinates of four points in 2D space, return whether the four points could construct a s ...

  10. Bootstrap列表组

    前面的话 列表组是Bootstrap框架新增的一个组件,可以用来制作列表清单.垂直导航等效果,也可以配合其他的组件制作出更漂亮的组件.本文将详细介绍Bootstrap列表组 基础列表组 基础列表组,看 ...