在了解jvm的结构之前,我们有必要先来了解一下操作系统的内存基本结构:
操作系统+jvm的内存简单布局
你应该不难发现,原来jvm的设计的模型其实就是操作系统的模型,基于操作系统的角度,jvm也就是一个应用(java.exe/javaw.exe),而基于class文件来说,jvm就是个操作系统,而jvm的方法区,也就相当于操作系统的硬盘区,所以方法区也被叫做permanent区,因为这个单词是永久的意思,也就是永久区。而java栈和操作系统栈是一致的,无论是生长方向还是管理的方式,至于堆嘛,虽然概念上一致目标也一致,分配内存的方式也一直(new,或者malloc等等),但是由于他们的管理方式不同,jvm是gc回收,而操作系统是程序员手动释放,所以在算法上有很多的差异.
看下面的图。
如下图。
下面你看我贴出的一个类的基本结构。
importjava.io.Serializable;
public final class ClassStruct extends Object implements Serializable{//1.类信息
//2.对象字段信息
private String name;
private int id;
//4.常量池
public final int CONST_INT=0;
public final String CONST_STR="CONST_STR";
//5.类变量区
public static String static_str="static_str";
//3.方法信息
public static final String getStatic_str() throws Exception{
return ClassStruct.static_str;
}
}
你将上面的代码注解和上面的那个字节码码内存块按标号对应一下,就会发现,其实内存的字节码块就是完整的把你整个类装到了内存而已。
所以各个信息段记录的信息可以从我们的类结构中得到。
1.类型信息:也就是public final class ClassStruct extends Object implements Serializable这段描述的信息提取
修饰符(public final)
是类还是接口(class,interface)
类的全限定名(Test/ClassStruct.class)
直接父类的全限定名(java/lang/Object.class)
直接父接口的权限定名数组(java/io/Serializable)
2.字段信息:也就是类似private String name;这段描述信息的提取
修饰符(pirvate)
字段类型(java/lang/String.class)
字段名(name)
3.方法信息:也就是对方法public static final String getStatic_str ()throws Exception的字节码的提取
修饰符(public static final)
方法返回值(java/lang/String.class)
方法名(getStatic_str)
参数需要用到的局部变量的大小还有操作数栈大小
方法体的字节码
异常表(throws Exception)
4.常量池:
4.1.直接常量:
4.1.1CONSTANT_INGETER_INFO整型直接常量池 public final int CONST_INT=0;
4.1.2CONSTANT_String_info字符串直接常量池 public final String CONST_STR=“CONST_STR”;
4.1.3CONSTANT_DOUBLE_INFO浮点型直接常量池
等等各种基本数据类型基础常量池
4.2.方法名、方法描述符、类名、字段名,字段描述符的符号引用
也就是所有编译器能够被确定,能够被快速查找的内容都存放在这里,它像数组一样通过索引访问,就是专门用来做查找的。
编译时就能确定数值的常量类型都会复制它的所有常量到自己的常量池中,或者嵌入到它的字节码流中。作为常量池或者字节码流的一部分,编译时常量保存在方法区中,就和一般的类变量一样。但是当一般的类变量作为他们的类型的一部分数据而保存的时候,编译时常量作为使用它们的类型的一部分而保存
5.类变量:
就是静态字段( public static String static_str=“static_str”;)
虚拟机在使用某个类之前,必须在方法区为这些类变量分配空间。
6.一个到classLoader的引用,通过this.getClass().getClassLoader()来取得为什么要先经过class呢?思考一下,然后看第七点的解释,再回来思考
7.一个到class对象的引用,这个对象存储了所有这个字节码内存块的相关信息。所以你能够看到的区域,比如:类信息,你可以通过this.getClass().getName()取得所有的方法信息,可以通过this.getClass().getDeclaredMethods(),字段信息可以通过this.getClass().getDeclaredFields(),等等,所以在字节码中你想得到的,调用的,通过class这个引用基本都能够帮你完成。因为他就是字节码在内存块在堆中的一个对象
8.方法表,如果学习c++的人应该都知道c++的对象内存模型有一个叫虚表的东西,java本来的名字就叫c++- -,它的方法表其实说白了就是c++的虚表,它的内容就是这个类的所有实例可能被调用的所有实例方法的直接引用。也是为了动态绑定的快速定位而做的一个类似缓存的查找表,它以数组的形式存在于内存中。不过这个表不是必须存在的,取决于虚拟机的设计者,以及运行虚拟机的机器是否有足够的内存
原文地址:http://blog.csdn.net/yfqnihao/article/details/8289363