谈java的内存分配
java程序运行时的内存结构分成:方法区,栈内存,堆内存,本地方法栈几种,栈和堆都是数据结构的
知识,如果不清楚,没关系,就当成一个不同的名字就好了,下面的讲解不需要用到他们的具体知识。
方法区:方法区存放装载的类数据信息包括:
1.基本信息:
1每个类的权限定名
2每个类的直接超类的权限定名(可约束类型的转换)
3该类是类还是接口
4该类型的访问修饰符
5直接超接口的权限定名的有序列表
2.每个已装载类的详细信息:
1运行时常量池:存放该类型所用的一切常量(直接常量和对其它类型,字段,方法的符号引用),它们
以数组形式通过索引被访问,是外部调用与类联系及类型对象化的桥梁。它是类文件(字节码)常量池
的运行时表示。(还有一种静态常量池,在字节码文件中)
2字段信息:类中声明的每一个字段的信息(名,类型,修饰符)。
3方法信息:类中声明的每一个方法的信息(名,返回类型,参数类型,修饰符,方法的字节码和异常类)
4静态常量
5到类classloader的引用:即到该类的类转载器的引用
6到类class的引用:虚拟机为每一个被装载的类型创建一个class实例,用来表示这个被装载的类。
栈内存
java栈内存以帧的形式存放在本地方法的调用状态(包括方法调用的参数,局部变量,中间结果等)
也就是说:方法中定义的一些基本类型的变量和对象的引用变量都在方法的栈内存中分配。
栈内存的构成
java栈内存由局部变量区,操作数栈,帧数据区组成
1:局部变量区一个以字为单位的数组,每个数组元素对应一个局部变量的值,调用方法时,将方法的
局部变量组成一个数组,通过索引来访问,若为非静态方法,则加入一个隐含的引用参数this,该参数
指向调用这个方法的对象,而静态方法则没有this参数
2.操作数栈也是一个数组,但是通过栈操作来访问,所谓操作数是那些被指令操作的数据,当需要对
参数操作时,如a=a+b;就将即将被操作的参数压栈,如将b和c压栈,然后由操作指令将他们弹出,并执行
操作。虚拟机将操作数栈作为工作区
3帧数据区处理异常量池解析,异常处理等
堆内存
对内存用来存放由new创建的对象和数组,在堆中分配的内存,由java虚拟机的自动垃圾回收器来管理
在堆中产生了一个数组或对象后,还可以在栈中定义一哥特殊的变量,让栈中这个变量的取值等于数
组或对象在堆内存中的首地址,栈中的这个变量就成为了数组或对象的引用变量。引用变量就相当于是
为了数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象
栈内存和堆内存比较
栈的优势是,存取速度比堆要块,仅次于寄存器,栈数据可以共享,但缺点是,存在栈中的数据大小
与生存期必须是确定的,缺乏灵活性,栈中主要存放一些基本类型的变量(int,short,long,byte,
float,double,boolean,char)和对象句柄。
栈有一个很重要的特性就是存在栈中的数据可以共享,
假设:
int a=3;
int b=3;
编译器先处理int a=3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没
找到,将3存放进来,然后将a指向3.接着同理b=3;在创建完b的引用变量后,因为在栈中已经有了这3个
值,便将直接指向3,这样出现了a与b同时均指向3的情况
这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4,
如果已经有了,则直接将a指向这个地址,因此,a值的改变不会影响到b的值,要注意这种数据的共享
与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况下a的修改并不会影响到b,它
是由编译器完成的,它有利于节省空间,
本地方法栈内存
java通过java本地接口JNI(java Native Interface)来调用其它语言编写的程序,在java里面用native
修饰符来描述一个方法是本地方法,这个了解下就好了
String的内存分配
String是一个特殊的包装类数据。可以用:
String str=new String("abc");
String stt="abc";
两种形式来创建,第一种是用new()来创建对象的,它会存放在堆中。没此调用一次就会创建一个新
的对象,
而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放“abc”,如果
没有,则将abc存放进栈,并令str指向"abc",如果已经有abc,则直接令str指向abc.
比较类里面的数值是否相等时,用equals()方法:当测试两个包装类的引用是否指向同一哥对象时,用==
,举例说明:
public class Test{
public static void main(String[] args){
String s1="abc";
String s2="abc";
System.out.println(s1==s2);//true
String s3=new String("abc");
String s4=new String("abc");
System.out.println(s3==s4);//false
System.out.println(s1==s3);//false
}
}
结果:
true
false
false
|