Java存储机制——栈、堆区别(变量,常量,String举例)

Java的6种存储储存地址及其解释

  1. 寄存器(register):这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。但是寄存器数量极其有限,所以寄存器根据编译器需求来进行分配,我们无法控制。
  2. 堆栈(常称为栈:stack):位于通用RAM中。它通过它的“堆栈指针”可以从处理器获得支持。堆栈指针若是往下移动,则分配新的内存,堆栈指针若是往上移动,则释放内存。这是一种快速有效的分配方法,仅次于寄存器。但是创建程序的时候,栈必须要知道存储在栈内数据的大小和确切生命值,因为要根据程序生成代码,以便上下移动堆栈指针。虽然这种存储方式快速,但是也失去了程序的灵活性,所以对象不存放在栈里面。
  3. 堆(heap):位于通用性的内存池(也位于通用RAM)中,用于存放所有Java的对象。堆不同于栈的好处就是:堆不需要知道自己需要分配多少的内存区域,也不需要知道存储的代码数据能够成活多久,因此,堆的内内存分配有很大的的灵活性。当需要创建一个对象的时候,只需要new一个,执行这行代码的时候堆就会分配内存。但是堆也为了这个灵活性付出了代价的,因为是运行过程中才分配的内存,所以速度就比较慢,比栈要慢很多
  4. 静态域(static storage):存放static定义的静态成员,也是程序运行时一直存在的数据。这里的静态是指在固定的位置。
  5. 常量池(constant storage):存放常量(public static final),即字符串常量、基本数据数据常量。常存放于代码内部,因为不会被改变。
  6. 非RAM存储:磁盘等永久存储空间

堆、栈、方法区的的存储内容

栈:

  • 每个线程都包含一个栈区,栈中只包含基本数据类型的值、对象和基本数据类型的引用。
  • 每个栈中的数据(基本数据类型和对象引用)都是私有的,其他栈不能访问

堆:

  • 存储的全部是实例对象
  • JVM只有一个堆被所有线程共享

方法区:

  • 也叫静态区,和堆一样被所有线程共享。
  • 方法区包含的都是整个程序永远唯一的元素,如class变量,static变量

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

int a = 1;
int b = 1;

编译器先处理int a = 1;首先在栈中创建一个int型的变量,然后查找有没有字面值为1的地址。如果没有找到,就开辟一个存放字面值为1的地址,然后a指向1的地址。在创建完a以后,已经存在字面值为1的地址,变量b在栈中找到字面值为1的地址,指向该地址。于是a,b同时指向1。这就是共享。

但是这种引用又与对象引用不相同。通过字面值的引用来修改值,不会导致另一个指向该字面值的引用的值也跟着改变。说起来比较拗口。下面解释一下

int i1 = 9; 
int i2 = 9;  
int i3 = 9;   
public static final int INT1 = 9;  
public static final int INT2 = 9;  
public static final int INT3 = 9; 

                                         

当将i2赋值7的时候

i2 = 7;

会继续上面的步骤,在栈中查找有没有字面值为7的地址。如果没有,在栈中开辟一个字面值为7的地址,然后i2指向7的地址,因此不会影响其他引用。

 提一下String类,这是一个特殊的包装类数据。

区别一下两种创建方式

1.String str = "abc";
2.String str = new String("abc");

创建方式1:

  1. 先定义一个名为str的String类的对象引用变量:String str;
  2. 在栈中查找有没有存放值为“abc”的地址,如果没有,就开辟一个存放字面值为“abc”的地址,接着新建一个String的对象string指向该地址,在栈中这个地址旁记下这个引用的对象string。如果有值为“abc”的地址,则查找对象string,并返回string的地址。
  3. 将str指向引用变量string的地址
  4. 也许你会觉得和  基本数据类型的引用  类似,没错就这么理解吧。
		String str1 = "字符串";
		String str3 = "字符串";
		System.out.println(str1 == str3);//true
  • 这里只创建了一个对象,但是两个引用变量指向了这个对象。 

创建方式2:

  1. new出来的对象都存放在堆里面,显而易见,此时两者已经地址已经不相等了
  2. 下面代码创建了三个对象,自行理解~
		String str1 = "字符串";
		String str2 = new String("字符串");
		String str3 = new String("字符串");
		System.out.println(str1 == str2);//false
		System.out.println(str3 == str2);//false

猜你喜欢

转载自blog.csdn.net/weixin_42621338/article/details/82931136