java内存区域介绍
我们先来介绍下虚拟机运行时数据区的结构:
我们项目中的每一个线程在运行时,都会有拥有自己独立的栈数据和程序计数器。程序计数器可以看作字节码命令的指示器,记录了下个需要执行的字节码指令,栈数据主要分为本地方法栈和java虚拟机栈。java虚拟机栈就是用来处理我们程序中代码生成的字节码的。
我们程序中的每个方法在执行时都会被分配给一个虚拟机栈帧,栈帧中包含局部变量表和操作数栈以及返回地址等,用来执行该方法生成的字节码。我们的java程序在编译期间编译器会自动帮我们添加一个默认参数,这个参数就是该方法所属类的引用,也就是我们开发中经常会用的this。this持有方法区中类对象的引用(注意类对象是被放在方法区的,而其他对象都是放在堆中的)。类对象中包含了类的基本信息,包括全限定名、简单名、字段列表、方法列表等等,而这些属性的值全部都被保存在常量池中。常量池又可以分为静态常量池和运行时常量池,接下来我们介绍常量池。
静态常量池和运行时常量池介绍
我们的java程序在编写完成时是以java文件的形式存在的,在完成编译后变成了class文件。如果大家比较了解class文件的话,应该会知道class文件中最重要的是常量池,类的所有属性,包括字段名、方法名等等的值都存储在class文件的常量池中,这里的常量池就是我们所说的静态常量池。这时类属性对class文件常量池中值的引用被称为符号引用,因为这时常量池中的值仍然仅仅是符号,不是具体的内存地址。符号引用到内存地址引用的转换要到运行期才会发生,所以我们称java程序是动态链接的。
当我们class文件被加载到内存中时,内存中同样存在一个常量池,这个常量池我们通常称为运行时常量池。但是这里的运行时常量池仅仅是一个泛称,而并不是说有这么一个大池子,实际上运行时常量池是字符串常量池、数字类型常量池等数据结构的统称。这里我们以字符串常量池举个?来说明静态常量池到运行时常量池的转变过程。虚拟机在将class文件加载到内存的过程中会先到class文件的常量池中寻找字符串类型的常量数据,找到后到内存中的运行时字符串常量池中寻找是否有相同的字符,若没有就在堆中创建一个字符串对象,并且在字符串常量池添加这个字符串的引用,同时也会将class中所有原本的引用全部都改成新的引用。字符串常量的使用能够大幅度的提升对象的利用率,减少程序中不必要的开销。