Java 基础(六)java JVM内存
Java虚拟机
内存结构
每个区域存储什么数据
java堆区存储:当java类实例化一个对象或者数组时,jvm会在堆中为其分配内存空间,并且jvm中只有一个堆所有的线程共享一块堆区域。
方法区:所有的线程共享一个方法区,方法区的大小可以通过程序运行时指定如初始化大小、最小值、最大值,
java栈区存储:
1、类型信息(Type Information)
每一个被加载的类型,在Java虚拟机中都会在方法区中保存如下信息:
1)、类型的全名(The fully qualified name of the type)
2)、类型的父类型的全名(除非没有父类型,或者弗雷形式java.lang.Object)(The fully qualified name of the typeís direct superclass)
3)、给类型是一个类还是接口(class or an interface)(Whether or not the type is a class )
4)、类型的修饰符(public,private,protected,static,final,volatile,transient等)(The typeís modifiers)
5)、所有父接口全名的列表(An ordered list of the fully qualified names of any direct superinterfaces)
类型全名保存的数据结构由虚拟机实现者定义。除此之外,Java虚拟机还要为每个类型保存如下信息:
1)、类型的常量池(The constant pool for the type)
2)、类型字段的信息(Field information)
3)、类型方法的信息(Method information)
4)、所有的静态类变量(非常量)信息(All class (static) variables declared in the type, except constants)
5)、一个指向类加载器的引用(A reference to class ClassLoader)
6)、一个指向Class类的引用(A reference to class Class)
1)、类型的常量池(The constant pool for the type)
常量池中保存中所有类型是用的有序的常量集合,包含直接常量(literals)如字符串、整数、浮点数的常量,和对类型、字段、方法的符号引用。常量池 中每一个保存的常量都有一个索引,就像数组中的字段一样。因为常量池中保存中所有类型使用到的类型、字段、方法的字符引用,所以它也是动态连接的主要对 象。详细信息参见第六章“The Java Class File”。
2)、类型字段的信息(Field information)
字段名、字段类型、字段的修饰符(public,private,protected,static,final,volatile,transient等)、字段在类中定义的顺序。
3)、类型方法的信息(Method information)
方法名、方法的返回值类型(或者是void)、方法参数的个数、类型和他们的顺序、字段的修饰符(public,private,protected,static,final,volatile,transient等)、方法在类中定义的顺序
如果不是抽象和本地本法还需要保存
方法的字节码、方法的操作数堆栈的大小和本地变量区的大小(稍候有详细信息)、异常列表(详细信息参见第十七章“Exceptions”。)
4)、类(静态)变量(Class Variables)
类变量被所有类的实例共享,即使不通过类的实例也可以访问。这些变量绑定在类上(而不是类的实例上),所以他们是类的逻辑数据的一部分。在Java虚拟机使用这个类之前就需要为类变量(non-final)分配内存
常量(final)的处理方式于这种类变量(non-final)不一样。每一个类型在用到一个常量的时候,都会复制一份到自己的常量池中。常量也像类变 量一样保存在方法区中,只不过他保存在常量池中。(可能是,类变量被所有实例共享,而常量池是每个实例独有的)。Non-final类变量保存为定义他的 类型数据(data for the type that declares them)的一部分,而final常量保存为使用他的类型数据(data for any type that uses them)的一部分。详情参见第六章“The
Java Class FileThe Java Class File”
5)、指向类加载器的引用(A reference to class ClassLoader)
每一个被Java虚拟机加载的类型,虚拟机必须保存这个类型是否由原始类加载器或者类加载器加载。那些被类加载器加载的类型必须保存一个指向类加载器的引 用。当类加载器动态连接时,会使用这条信息。当一个类引用另一个类时,虚拟机必须保存那个被引用的类型是被同一个类加载器加载的,这也是虚拟机维护不同命 名空间的过程。详情参见第八章“The Linking Model”
6)、指向Class类的引用(A reference to class Class)
Java虚拟机为每一个加载的类型创建一个java.lang.Class类的实例。你也可以通过Class类的方法:
public static Class forName(String className)来查找或者加载一个类,并取得相应的Class类的实例。通过这个Class类的实例,我们可以访问Java虚拟机方法区中的信息。具体参照Class类的JavaDoc。
2、方法列表(Method Tables)
为了更有效的访问所有保存在方法区中的数据,这些数据的存储结构必须经过仔细的设计。所有方法区中,除了保存了上边的那些原始信息外,还有一个为了加快存 取速度而设计的数据结构,比如方法列表。每一个被加载的非抽象类,Java虚拟机都会为他们产生一个方法列表,这个列表中保存了这个类可能调用的所有实例 方法的引用,报错那些父类中调用的方法。详情参见第八章“The Linking Model”
本地方法栈:
本地方法栈其实和java栈作用是一样的,只不过服务的对象不一样,java栈为java虚拟机执行java方法服务而本地方法栈为虚拟机执行native方法服务,这两个区域没有明显的区别,有的虚拟机将二者合二为一了,如sun hotspot将他们写在了一起统称为栈。
然后heap又可以细分为如下几个区域:
之所以把堆再进行细微划分也是为了合理利用内存空间,提高代码的执行效率。
总结:
这只是一个宏观视图具体到代码如何动态的在内存中变化,还需要一点一点的分析这一过程,每一步都包含了很多内容需要我们深入分析虚拟机里面,才会对它的运行机制比较理解。