首先需要说明的是这里说的内存分配,不包含现在热门的栈上分配等方式,只针对最基础的分析。
在JVM的结构中,主要包含:方法区,堆,JAVA栈,本地方法栈,程序计数器。
其中:方法区,堆为各线程共享的区域,JAVA栈,本地方法栈和程序计数器为线程私有。
当类(接口)在经过编译为class文件后,再由类(接口)加载器加载到内存中,当前类(接口)中包含的信息,如:类(接口)的描述,类(接口)中的成员变量,方法等信息都会加载到方法区中,编译期间产生的“常量”和“对象字符串引用”都会加载到方法区的常量池(运行时常量池)中(字符串类型的保存到方法区的String常量池中),当新建某个类的实例时,虚拟机会在当前的堆中分配一块空间做为新建类的保存区域,将栈帧常量池中对新建对象引用的值设定为可以查询到当前堆对象的地址(可以是新建对象在堆中的直接地址,也可能是新建对象在堆中的句柄地址),PC计数器保存当前执行指令地址,当当前执行的方法为本地方法时,PC计数器中则为空。
在这里,可能会经常问道一个问题,String 到底创建了几个的问题:
1.
String aa="abc";
创建了一个字符串"abc",字符串"abc"位于方法区的常量池中;
2.
String aa="abc";
String bb="abc";
创建了一个字符串"abc",bb是指向了第一句中创建的字符串地址,字符串"abc"位于方法区的常量池中;
3.
String bb=new String("abc");
创建了两个字符串,一个是"abc",一个是新建的String对象,"abc"位于方法区,新建的对象在堆中。
4.
String aa="abc";
String bb=new String("abc");
创建了两个字符串,第一句中的"abc"是新建的,第二句中的"abc"是指向第一句中"abc"的地址,然后在新建一个String对象保存到堆中,最后返回的是堆的地址,所以aa和bb是不等的。
在JVM的结构中,主要包含:方法区,堆,JAVA栈,本地方法栈,程序计数器。
其中:方法区,堆为各线程共享的区域,JAVA栈,本地方法栈和程序计数器为线程私有。
当类(接口)在经过编译为class文件后,再由类(接口)加载器加载到内存中,当前类(接口)中包含的信息,如:类(接口)的描述,类(接口)中的成员变量,方法等信息都会加载到方法区中,编译期间产生的“常量”和“对象字符串引用”都会加载到方法区的常量池(运行时常量池)中(字符串类型的保存到方法区的String常量池中),当新建某个类的实例时,虚拟机会在当前的堆中分配一块空间做为新建类的保存区域,将栈帧常量池中对新建对象引用的值设定为可以查询到当前堆对象的地址(可以是新建对象在堆中的直接地址,也可能是新建对象在堆中的句柄地址),PC计数器保存当前执行指令地址,当当前执行的方法为本地方法时,PC计数器中则为空。
在这里,可能会经常问道一个问题,String 到底创建了几个的问题:
1.
String aa="abc";
创建了一个字符串"abc",字符串"abc"位于方法区的常量池中;
2.
String aa="abc";
String bb="abc";
创建了一个字符串"abc",bb是指向了第一句中创建的字符串地址,字符串"abc"位于方法区的常量池中;
3.
String bb=new String("abc");
创建了两个字符串,一个是"abc",一个是新建的String对象,"abc"位于方法区,新建的对象在堆中。
4.
String aa="abc";
String bb=new String("abc");
创建了两个字符串,第一句中的"abc"是新建的,第二句中的"abc"是指向第一句中"abc"的地址,然后在新建一个String对象保存到堆中,最后返回的是堆的地址,所以aa和bb是不等的。