java内存中数据存储位置
2018-09-05 本文已影响40人
第四风111
java内存分配
- 寄存器:程序无法控制,读写最快!
- 栈:存放局部变量和对象的引用值,而对象本身则放在堆中(自动回收),可数据共享。
- 堆:程序运行期被动态创建,存放在堆中。手动回收或者系统gc回收。
- 静态域:存放对象中对象的static成员。
- 常量池:存放常量。
存储位置
- 先看一段程序吧:
int i=5;
int j=5;
那么这段程序中,内存发生了什么变化呢,首先会开辟一个i的存储区,然后会检查栈中有没有5这个值,如果没有,则保存到栈中,然后让i=5,接着开辟一个j的存储区,检查栈中是否有5,如果有,这直接让j=5。即所谓的栈内数据共享。
- 再看一段程序
String s1 = "abc";
String s2 = new String(“abc”);
- String s = ”abc“的工作过程可以分为以下几个步骤:
(1)定义了一个名为"s"的String类型的引用。
(2)检查在常量池中是否存在值为"abc"的字符串对象;
(3)如果不存在,则在常量池(字符串池)创建存储进一个值为"abc"的字符串对象。如果已经存在,则跳过这一步工作。
(4)将对象引用s指向字符串池当中的”abc“对象。 - String s = new String(”abc“)的步骤则为:
(1)定义了一个名为"s"的String类型的引用。
(2)检查在常量池中是否存在值为"abc"的字符串对象;
(3)如果不存在,则在常量池(字符串池)存储进一个值为"abc"的字符串对象。如果已经存在,则跳过这一步工作。
(4)在堆中创建存储一个”abc“字符串对象。
(5)将对象引用指向堆中的对象。
这里指的注意的是,采用new的方式,虽然是在堆中存储对象,但是也会在存储之前检查常量池中是否已经含有此对象,如果没有,则会先在常量池创建对象,然后在堆中创建这个对象的”拷贝对象“。这也就是为什么有道面试题:String s = new String(“xyz”);产生几个对象?的答案是:一个或两个的原因。因为如果常量池中原来没有”xyz”,就是两个。
- 最后,借助网上看到的一个例子帮助对栈内存,堆内存的存储进行理解:
class BirthDate {
private int day;
private int month;
private int year;
public BirthDate(int d, int m, int y) {
day = d;
month = m;
year = y;
}
省略get,set方法………
}
public class Test{
public static void main(String args[]){
int date = 9;
Test test = new Test();
test.change(date);
BirthDate d1= new BirthDate(7,7,1970);
}
public void change1(int i){
i = 1234;
}
- 对于以上这段代码,date为局部变量,i,d,m,y都是形参为局部变量,day,month,year为成员变量。下面分析一下代码执行时候的变化:
- main方法开始执行:int date = 9; date局部变量,基础类型,引用和值都存在栈中。
- Test test = new Test(); test为对象引用,存在栈中,对象(new Test())存在堆中。
- test.change(date); 调用change(int i)方法,i为局部变量,引用和值- 存在栈中。当方法change执行完成后,i就会从栈中消失。
- BirthDate d1= new BirthDate(7,7,1970);调用BIrthDate类的构造函数生成对象。d1为对象引用,存在栈中;
- 对象(new BirthDate())存在堆中;其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中;day,month,year为BirthDate对象的的成员变量,它们存储在堆中存储的new BirthDate()对象里面;
- 当BirthDate构造方法执行完之后,d,m,y将从栈中消失。
- main方法执行完之后。date变量,test,d1引用将从栈中消失,new Test(),new BirthDate()将等待垃圾回收器进行回收。
参考文章:https://blog.csdn.net/qq_36838191/article/details/80248182