layout: post
title: 深入JAVA虚拟机_结构
categories: JVM JAVA
description: 深入JAVA虚拟机_结构
keywords: JVM JAVA
线程计数器
較小的内存區塊,用於記錄當前綫程的字節碼執行到了第几行,字節碼解釋器通過計數器獲取下一條指令,每個程序計數器用來記錄一個綫程的
行號,所以它是綫程私有的如果計數器執行的是JAVA方法,則計數器記錄的是執行的虛擬機字節碼指令地址。
如果計數器執行的是一個本地方法,則計數器為Undefined由於程序計數器只記錄當前指令地址嗎,所以不存在内存溢出的情況,所以程序計數器也是所有jvm内存區域中唯一一個沒有定義>OutOfMemoryError的区域。
虚拟机栈
綫程私有
一个线程一个栈,一个方法一个栈帧
虚拟机栈表示Java方法执行的内存模型,每调用一个方法就会为每个方法生成一个栈帧(Stack Frame),用来存储局部变量表、操作数栈、动
态链接、方法出口等信息虚拟机栈是一个后入先出的栈。栈帧是保存在虚拟机栈中的,栈帧是用来存储数据和存储部分过程结果的数据结构,同时也被用来处理动态链接Dynamic Linking、方法返回值和异常分派(Dispatch Exception)。线程运行过程中,只有一个栈帧是处于活跃状态,称为“当前活跃栈帧”,当前活动栈帧始终是虚拟机栈的栈顶元素。
动态连接: 每个栈帧都包含一个指向运行时常量池中该栈帧所属性方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。在Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化称为静态解析。另外一部分将在每一次的运行期期间转化为直接引用,这部分称为动态连接。
堆區
綫程共享
新生代 老年代
年轻代(Young Generation)
对象在被创建时,内存首先是在年轻代进行分配(注意,大对象可以直接在老年代分配)。当年轻代需要回收时会触发>Minor GC(也称作Young GC)。
年轻代由Eden Space和两块相同大小的Survivor Space(又称S0和S1)构成,可通过-Xmn参数来调整新生代大小,也可.
通过-XX:SurvivorRadio来调整Eden Space和Survivor Space大小。不同的GC方式会按不同的方式来按此值划分Eden >Space和Survivor Space,有些GC方式还会根据运行状况来动态调整Eden、S0、S1的大小。年轻代的Eden区内存是连续的,所以其分配会非常快;同样Eden区的回收也非常快(因为大部分情况下Eden区对象存活>时间非常短,而Eden区采用的复制回收算法,此算法在存活对象比例很少的情况下非常高效,后面会详细介绍)。
如果在执行垃圾回收之后,仍没有足够的内存分配,也不能再扩展,将会抛出OutOfMemoryError:Java Heap Space异
常。老年代(Old Generation)
1.老年代用于存放在年轻代中经多次垃圾回收仍然存活的对象
2.存放大对象,可以通过启动参数设置->XX:PretenureSizeThreshold=2048,表示超过多大时就不在年轻代分配,而是
直接在老年代分配。此参数在年轻代采用Parallel Scavenge GC时无效,因为其会根据运行情况自己决定什么对象直接在
老年代上分配内存;
3.存放大的数组对象,且数组对象中无引用外部对象。当老年代满了的时候就需要对老年代进行垃圾回收,老年代的垃圾回收称作Major GC(也称作Full GC)。
老年代所占用的内存大小为-Xmx对应的值减去-Xmn对应的值。
本地方法棧
为线程私有。线程在调用本地方法时,来存储本地方法的局部变量表,本地方法的操作数栈等等信息。
该方法的实现由非java语言实现,比如C语言实现。你可以告知JVM编译器去调用一个C语言编写的方法。java作为高级编程语言,当对一些底层的代码实现,java实现起来难度大,编程效率也很低下。本地方法就很好的解决了这个问题
该线程首先调用了两个Java方法,而第二个Java方法又调用了一个本地方法,这样导致虚拟机使用了一个本地方法栈。图中的本地方法栈显示为 一个连续的内存空间。假设这是一个C语言栈,期间有两个C函数,他们都以包围在虚线中的灰色块表示。第一个C函数被第二个Java方法当做本地方法调用, 而这个C函数又调用了第二个C函数。之后第二个C函数被第二个Java方法当做本地方法调用,而这个C函数又调用了第二个C函数。之后第二个C函数又通过 本地方法接口回调了一个Java方法(第三个Java方法)。最终这个Java方法又调用了一个Java方法(他成为图中的当前方法)
方法區
綫程共享
主要存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,eg: spring 使用IOC或者AOP创建bean时,或者使用cglib,反射的形式动态生成class信息等异常
当方法区无法满足内存分配需求时,将抛出OutOfMemoryError。
运行时常量池溢出:比如一直往常量池加入数据,就会引起OutOfMemoryError异常。