2、JVM 运行

 

1、方法区-Method Area

线程共享,存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等等。(HotSpot虚拟机上开发部署人员更愿意成为“永久代”,Permanent Generation)。

 

1.1、类型信息

  • 类型的全限定名
  • 超类的全限定名
  • 直接超接口的全限定名
  • 类型标志(该类是类类型还是接口类型)
  • 类的访问描述符(public、private、default、abstract、final、static)

1.2、类型的常量池

(该部分是独有的,然后运行时,把该部分加载进运行时常量池,当调用时则从符号引用解析为直接引用,但是有些确定的方法会直接转换,比如静态方法,比如构造方法)

存放该类型所用到的常量的有序集合,包括直接常量(如字符串、整数、浮点数的常量)和对其他类型、字段、方法的符号引用。常量池中每一个保存的常量都有一个索引,就像数组中的字段一样。因为常量池中保存中所有类型使用到的类型、字段、方法的符号引用,所以它也是动态连接(栈中对应的方法指向这个引用)的主要对象(在动态链接中起到核心作用)。

1.3、字段信息(该类声明的所有字段)

  • 字段修饰符(public、protect、private、default)
  • 字段的类型
  • 字段名称

1.4、方法信息

方法信息中包含类的所有方法,每个方法包含以下信息:

  • 方法名 
  • 方法的返回类型(包括void) 
  • 方法参数的类型、数目以及顺序 
  • 方法修饰符(public,private,protected,static,final,synchronized,native,abstract)

针对非本地方法,还有些附加方法信息需要存储在方法区内:

  • 方法字节码 
  • 方法中局部变量区的大小、方法栈帧 
  • 异常表 

1.5、类变量(静态变量)

指该类所有对象共享的变量,即使没有任何实例对象时,也可以访问的类变量。它们与类进行绑定。

1.6、指向类加载器的引用

每一个被JVM加载的类型,都保存这个类加载器的引用,类加载器动态链接时会用到。

1.7、指向Class实例的引用

类加载的过程中,虚拟机会创建该类型的Class实例,方法区中必须保存对该对象的引用。通过Class.forName(StringclassName)来查找获得该实例的引用,然后创建该类的对象。

1.8、方法表

为了提高访问效率,JVM可能会对每个装载的非抽象类,都创建一个数组,数组的每个元素是实例可能调用的方法的直接引用,包括父类中继承过来的方法。这个表在抽象类或者接口中是没有的,类似C++虚函数表vtbl。

2、堆-Heap

JVM内存底层结构:

 

  • VM内存划分为堆内存和非堆内存,堆内存分为年轻代(Young Generation)、老年代(Old Generation),非堆内存就一个永久代(Permanent Generation)。
  • 年轻代又分为Eden和Survivor区。Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例是8:1:1。

堆内存用途:存放的是对象,垃圾收集器就是收集这些对象,然后根据GC算法回收。

非堆内存用途:永久代,也称为方法区,存储程序运行时长期存活的对象,比如类的元数据、方法、常量、属性等。

2.1、JDK1.8之前

 

一个对象被创建以后首先被放到的Eden内存中,如果存活期超两个Survivor之后就会被转移到长时内存中(Old Generation)中。永久内存中存放着对象的方法、变量等元数据信息。如果永久内存不够,会发生错误:java.lang.OutOfMemoryError: PermGen

2.1、JDK1.8之后

把存放元数据中的永久内存从堆内存中移到了本地内存(native memory)中。

 

永久内存就不再占用堆内存,它可以通过自动增长来避免JDK7以及前期版本中常见的永久内存错误(java.lang.OutOfMemoryError: PermGen)。当然JDK8也提供了一个新的设置Matespace内存大小的参数,通过这个参数可以设置Matespace内存大小,这样我们可以根据自己项目的实际情况,避免过度浪费本地内存,达到有效利用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章