码迷,mamicode.com
首页 > 编程语言 > 详细

Java虚拟机

时间:2018-06-21 00:02:58      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:模型   rom   除了   回收   卸载   runtime   werror   output   double   

Java内存区域

运行时数据区域

程序计数器(Program Counter Register)

  • 较小的内存空间,是当前线程执行的字节码的行号的指示器。字节码解释器通过改变计数器的值来获取下一条字节码指令,分支、循环、跳转、异常处理、线程恢复都靠它完成.
  • 每个线程都有自己的一个计数器,线程之间计数器互不影响.
  • 执行Native方法时,计数器不起作用,值为空(Undefined)。
  • 此区域是唯一没有规定OOM的区域.

Java虚拟机栈 Java Virtual Machine Stack

  • 归属线程所有,生命周期与归属的线程相同。
  • 虚拟机栈描述的是Java方法执行的内存模型:
    • 方法执行时会创建栈帧(Stack Frame)存储局部变量表、操作数栈、动态链接、方法出口等.
    • 方法的调用到执行完成的过程,对应其栈帧从虚拟机栈中入栈到出栈的过程.
  • 局部变量表存放编译器可知的基本数据类型、对象引用;long、double因为长度为64bit,会占用两个Slot,其他则占用一个,由此可知局部变量表的内存空间在编译期就完成了分配,方法运行时不改变其大小。
  • 虚拟机栈中规定的两种异常情况:
    • StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度.
    • OutOfMemoryError:虚拟机栈动态扩展内存时,无法申请到足够的内存.

本地方法栈 Native Method Stack

  • 类似于虚拟机栈,区别是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈为Native方法工作;Native方法指Java调用的C/C++语言的函数.
  • 本地方法栈区域也会抛出StackOverFlowError & OutOfMemoryError异常。

Java堆 Java Heap

  • JVM中内存最大的一块,所有线程共享,在虚拟机启动时创建。几乎所有对象实例、数组都在这里诞生。
  • Java堆是垃圾回收的主要区域,又称GC(Garbage Collected Heap)堆。
  • 当堆中没有内存分配实例,并且无法扩展时,抛出OOM异常。
  • Java堆可以处于物理上的不连续的内存空间中,只要逻辑上是连续的即可。

  • 堆空间的内存细分

    技术分享图片
    • Young Generation:新生代,包含了Eden、S0(FromSurvivor)、S1(ToSurvivor);由于新生代上的对象存活时间很短暂,所以此区一般采用标记-清理算法GC.
    • Old Generation:老年代,经过多次GC后仍然存活的对象(每个对象都有一个对象年龄计数器),此区域采用一般采用复制算法GC;大对象,如数组,直接进入老年代.
    • Permanent:永久代,存放不变对象,类、方法、字符串等,见以下方法区。
  • 堆内存的分代回收
    1. 大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡。Eden区是连续的内存空间,因此在其上分配内存极快.
    2. 当Eden区满的时候,执行Minor GC,将消亡的对象清理掉,并将剩余的对象复制到一个存活区Survivor0(此时,Survivor1是空白的,两个Survivor总有一个是空白的).
    3. 此后,每次Eden区满了,就执行一次Minor GC,并将剩余的对象都添加到Survivor0.
    4. 当Survivor0也满的时候,将其中仍然活着的对象直接复制到Survivor1,以后Eden区执行Minor GC后,就将剩余的对象添加Survivor1(此时,Survivor0是空白的).
    5. 当两个存活区切换了几次(HotSpot虚拟机默认15次,用-XX:MaxTenuringThreshold控制,大于该值进入老年代)之后,仍然存活的对象(其实只有一小部分,比如,我们自己定义的对象),将被复制到老年代.
    6. 总结:Eden区是连续的空间,且Survivor总有一个为空;经过一次GC和复制,一个Survivor中保存着当前还活 着的对象,而Eden区和另一个Survivor区的内容都不再需要了,可以直接清空,到下一次GC时,两个Survivor的角色再互换。因此,这种方 式分配内存和清理内存的效率都极高,这种垃圾回收的方式就是著名的“停止-复制(Stop-and-copy)”清理法(将Eden区和一个Survivor中仍然存活的对象拷贝到另一个Survivor中).

方法区 Method Area

  • 所有线程共享,别名No-Heap(非堆)用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。也叫Permanent Generation(永久代);之所以名为永久代,是因为HotSpot将GC从堆延伸至了方法区。(对于其他虚拟机IBM J9等来说是不存在永久代的概念的)
  • 与Java堆一样,是各个线程共享的内存区域,它用于存储 已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
  • 并非被称为永久代,其中的数据就永久了,当类型卸载、常量池回收时也会发生GC,但是比较少见。
  • 当此区无法分配新内存时,抛出OOM异常。

运行时常量池 Runtime Constant Pool

  • 属于方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
  • 无法申请到内存时,抛出OOM异常.

直接内存

  • 直接内存不是JVM运行时的一部分,但是Java可以通过NIO(New Input/Output),引入Channel和Buffer的I/O方式,它可以用native方法申请堆外内存,然后通过JVM堆中的DirectByteBuffer对象操作这块内存,此时申请内存是通过Unsafe.allocateMemory方法实现的.

对象访问

  • 句柄访问方式:Java堆中分配一块内存作为句柄池,reference中存储对象的句柄地址,句柄中则包含实例数据指针和类型数据指针;此方式的好处在于句柄地址稳定,对象变动时,只需修改句柄,而reference不需改动.
  • 直接指针访问方式:Java堆对象中存放访问类型数据信息,reference直接存储对象地址;这种做法的好处是速度快,节省了一次指针定位的开销.

Java虚拟机

标签:模型   rom   除了   回收   卸载   runtime   werror   output   double   

原文地址:https://www.cnblogs.com/swanspouse/p/9206464.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!