java 数据存储区,主要以下五种:

  一、寄存器

  寄存器是集中在CPU指令的缓存区,是CPU直接作为数据交换,存取速度最快,一般用于复杂运算操作,不建议存放大数据,因寄存器数量有限,只存放要求非常快的数据,JAVA是不能直接操作寄存器。

  二、堆栈区

  堆栈,存放在RAM,也叫随机存储器,存取速度快,仅次于寄存器,以栈的方式进行存储,具有先进后出的特性。有一个叫堆栈指针直接跟CPU打招呼,向上移动则入栈(分配内存空间),向下移动则出栈(释放内存空间),故堆栈的内存分配/释放就是通过上下移动堆栈指针来操作的。基本类型(byte, short, int, float, double, boolean, char, long)8大类型(包括方法的参数和局部变量,不包括类字段)和引用类型的地址就存放于此。因堆栈是在编译器编译时要确定其大小和生命周期,故能确定什么时候能释放。

  优点:存取速度快。缺点:必须确定大小和生命周期,灵活性不够。

  三、堆区

  堆,也是存放在RAM,程序在编译时不需要指定空间大小,只在运行时才确定其大小,故增加了灵活性。所有以new引用类型的对象都存放于此,如: Object o = new Object(); 先在堆里分配一个空间用来存放Object对象,再在堆栈里分配一个空间标识为o,将这个空间存放刚刚分配的Object对象的内存地址。如果是数组,则堆栈存放的是数组的首地址。其中堆区也有个堆指针,堆指针总是指向当前分配的内存地址,如果要创建,则向下移动一格尚未分配的空间,不用再去整个堆区里查找未用空间,加速了分配内存速度,这是JVM做了优化。

  优点:因为在运行时动态指定大小,故灵活性好。缺点:存取速度慢。

  四、常量池

  常量池,主要用来存放永久不变的值(永久是指从程序运行到结束),如String,static final关键字修饰的变量 。这里要特别说明String,String本身是引用类型,因字符串在程序用的概率非常高,为了提高重用性和节省内存空间,JVM都会把所有出现过的字符串固定存放在常量池里,当下次用到这个字符串时,会先从常量池里找,如有则返回引用地址,没有则创建一个并返回引用地址。例如下:

  例1:

  String s1 = "abc";

  String s2 = "bcd";

  String s3 = "abc";

  String s4 = s2;

  S1创建在常量池没找到字符串“abc", 则新创建并返回内存地址(假设0x01)给s1; s2也是一样,创建并返回内存地址(0x02);s3因为"abc"已经存在常量池,故返回存在的内存地址0x01给s3; s4直接取s2所引用的内存地址0x02;

  例2:

  String s1 = "a";

  String s2 = new String("a");

  String s3 = new String("b");

  String s4 = "a".intern();

  s1就不说了,跟例1一样; s2是用new一个对象,不是直接赋值,过程是:先在常量池里找是否存在”a",如果不存在则新创建,如果存在则忽略此步,然后再在堆里创建String对象并存放“a",并返回堆里的引用地址(0x03)给s2,所以用new String会创建1个或2个对象; s3原理同上; s4是用对象的intern方法,该方法表示返回常量的内存地址。

  String 字符串一创建就不能更改,故开发者要提倡尽量少创建频率更改的字符串,如果确实有需要更改,应该用StringBuilder(非线程安全)或StringBuffer(线程安全)。String str = "a" + "b" + "c", 对于字符串的+,编译器已经对此进行了优化,编译后的代码等效为String str = "abc";

  五、非RAM区

  非RAM区,是不存在内存里,如硬盘或持久化流。
  

  总结:从以上的存储区可以看出,JAVA能操作到的,堆栈是最快的,能用基本类型解决问题就尽量用基本类型,基本类型还有个包装类,如int对应Integer,包装类是引用类型,创建的对象也是存在堆区里,如无特殊需要,尽量不要用包装类;关于常量池,尽量不要存太多,因为常量池永远不会变,生命周期从创建到程序结束为止,尤其是大数据对象,占用空间大,还有个是不经常用到的常量也尽量不要存放于此,节省内存使用概率。