Java中栈、堆和常量池

时间:2022-12-27 07:57:41

写这篇文章的目的,只想把java 栈、堆、常量池的概念理清楚,并且弄清数据存储方式,这里尤其是指java string类的声明和实例化时的数据存储。网上这方面资料很多,但是说法都不尽相同。以下是我自己的理解,也是参考一些网站资料,并整理成文。由于作者水平有限,不当指出,欢迎指出。

介绍:

栈(stack)和堆(heap)一样存储在计算机RAM中。概念上可以参考:

http://droidyue.com/blog/2014/12/07/differences-between-stack-and-heap-in-java/

1. 栈:存放基本类型的变量数据和对象的引用(就是一个名字),对象本身不存放在栈中,而是存放在堆或者常量池中。栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。栈区内存由编译器自动分配释放,具体方法执行结束之后,系统自动释放JVM内存资源。

2. 堆:存放所有new出来的对象或数组。堆内存中的对象对所有线程可见,可以被所有线程访问。jvm不定时查看堆中的对象,如果没有引用指向这个对象就回收。

3. 常量池:存放字符串常量和基本类型常量(public static final)。

1.声明和实例化

声明:A a=null ,声明一个A类的对象a,a放在栈中。

实例化:a=new A() ,实例化这个对象a,new A() 放在堆中。

2. String s=newString("a")Strings=”a”创建了几个对象?

String s= newString("a")创建了两个对象,一个是在常量池中,一个是在堆内存中,常量池的为"a",堆内存中为new String()。变量s指向该new string()对象,而该对象又指向在常量池中的字符串常量”a”。注意的是,在new的时候java虚拟机先去内存的常量池中查找”a”这个对象,如果有就不创建了,直接把堆中的对象指向该字符串。

String s="a"的意思就是在栈中创建一个字符串类型的变量s,并且变量s直接指向常量池中的字符串对象”a”,省去了中间的堆内存中的对象。注意的是,String s = "a",这行代码被执行的时候,java虚拟机首先在字符串池中查找是否已经存在了值为"a"这么一个对象,它的判断依据是String类equals(Object obj)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。

Strings1=”a”

String s2=”a”

String s3=”b”

String s4=newString(“a”)

String s5=newString(“b”)

 Java中栈、堆和常量池

 

对于字符串,其对象的引用(这里指:s1,s2,s3,s4,s5)都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期new出来的(一旦new就会开辟新的堆内存)才存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。

参考:

http://www.cnblogs.com/ydpvictor/archive/2012/09/09/2677260.html

http://bbs.itheima.com/thread-117068-1-1.html

3. 数据存放位置

int a=3;                    3存放在常量池

char c = 'a';               'a'存放在常量池

boolean b = true;    true存放在常量池

byte byt = 2;             2存放在常量池

String str = "abc"; "abc"存放在常量池

String str1 = new String("abc");     new String("abc")存放在堆中

4. 其他参考

http://zhidao.baidu.com/link?url=j1Aj-hmv4txPic868N3r2QZSgrwp4psA4urERlAtSkT7Bk-o4_xLO8ABwrsrbuzUVVpl-H6yuJ3N87xo62TYOq

http://zhidao.baidu.com/link?url=8P0rLN-TcbNgDl1r-BD6Z4NiIgZhRBGirD4XipDVEwipVNZqS5_YEYP7BtKujz0mQRbpNe_yyyXi7-SVloTwIq