java 内存区域介绍

来源:互联网 发布:中国报学史读后感知乎 编辑:程序博客网 时间:2024/05/16 15:44

java 内存区域介绍

 java 虚拟机运行时数据区



程序计数器

     javac编译器完成了词法分析、语法分析到抽象语法树,再遍历树生成线性指令流。

程序计数器是一块较小的内存空间,可以看成当前线程的线性指令流的行号指示器,字节码解释器通过改变这个值来选取下一条需要执行的字节码指令。

    由于java线程是抢占式的,且一个处理器同一时间只会执行一条线程中的指令,为了线程切换能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,保证线程之间计数器互不影响。

    如果执行的是java方法,计数器记录的是正在执行的虚拟机字节码指令的地址,如果是native方法,这个计数器的值为空

 

执行引擎

    根据程序计数器,栈,堆进行调用。

java对方法指令的解释执行,执行方式为经典 诺依曼体系中的FDX循环方式,即获取下一条指令,解码并分派,然后执行。实现FDX循环时有switch-thread,token_thread,direct-thread,subroutine-thread,inline-threading

switch-thread 是最简单的形式:

 

token-thread

 

java并没有在解释器做太复杂的处理用的就是token-thread

direct-thread,subroutine-thread,inline-threading请自行查阅资料查询

本地方法栈

包括本地方法接口,本地方法库,这一块时c/c++实现(有想了解的自己查阅资料)

java虚拟机栈

    栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构。

虚拟栈就是有N个栈帧形成的栈结构,每调用一个方法都会形成一个栈帧,

    栈帧包括局部变量表,操作数栈,动态链接和方法返回等构成

   1.局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。

局部变量表的容量以变量槽为最小单位,为了尽可能节省栈帧空间,局部变量表的slot是可以重用的,超过作用域的局部变量可以被重用

   2.操作数栈也长称为操作栈,后入先出的数据结构。当方法开始执行时,操作数栈是空的,在方法执行过程中,会有各种字节码指令,往操作数栈写入和提取内容。

demo:整数加法字节码指令iadd 在运行时候操作最接近栈顶的两个元素,已经存入操作数栈顶的两个数值,当执行这个指令时,会将这两个int值出栈并相加,然后将相加的结果入栈。

   3动态链接,每个栈帧都包含一个指向运行时常量池中改栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接。java多态的实现就是根据运行时将方法转为实际类所属方法的直接引用

  4.方法返回地址,java中有两种情况会退出方法,一种是遇到退出的字节码指令,另一种是遇到异常。无论采用何种退出方式,在方法退出之后都需要返回方法调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。方法退出的实际过程等同于把当前栈帧出栈,退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值压入调用者栈帧的操作数栈中,调整pc计数器的值以指向方法调用指令的后面一条指令等。

 

java堆

java堆划分为1:年轻代 (包括edge,s0,s1) ,2.年老代  3.方法区

 

划分原因如下:

   jvm堆的划分主要是从垃圾回收的角度考虑的。

一。主流的垃圾回收判定垃圾的算法有以下两种:

1.引用计数器法

   该方法主要实现为:给每个对象添加一个引用计数器,每当有一个地方引用时,就计数器加1,当引用失效时,计数器减1,每次回收时回收那些引用计数器为零的对象。

(改算法的优点是实现简单,判定效率高,缺点无法解决互相引用的问题(例:如果A引用B,B反过来引用A就永远回收不了了))

2.可达性分析算法

   该方法实现如下,通过一系列称"GC roots" 的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC roots没有任何引用链相连,则证明此对象是不可用的。

 

二。垃圾回收算法主要有如下几种

 1.标记-清除

思路如下:第一步根据查找垃圾的算法,找到那些对象不可用,把这些对象标记为垃圾。标记完成后统一回收。

该算法主要不足点为:1效率问题。标记和清除两个步奏效率都不高。2空间问题:标记清除之后会产生大量的不连续的内存空间(俗话说的内存碎片)。碎片过多导致以后运行过程中需要分配大对象时,无法找到足够的连续空间不得不提前触发GC.

2. 复制算法

  为了解决效率问题,一种称为复制的算法出现了。他将可用内存按容量划分为大小相等的两块。每次只使用其中一块。当一块内存用完了,就将还存活的对象复制到另一块内存上。然后将已使用的内存空间一次性清理掉。

  算法优点。实现简单,运行高效(当然如果存活对象比较多的话也影响效率),没有内存碎片。缺点:白白浪费了一半内存。

 

3.标记-整理算法

该算法和标记-清除算法一致,就是最后多了一步碎片整理

 

总结:jvm根据以上算法而设计了年轻代,年老带,方法区:

 

1.jvm团队认位大部分对象都是朝生幕死的,对于这些对象由于存活率不高而采用了

复制算法,jvm 对复制算法进行了改动采用了eage ,s0 ,s1 (s0,s1就是复制算法的两个内存,冗余来了eage为了节省内存) ,默认比例是8:1:1,不同的回收方式比例不同,有兴趣自己查阅资料。

2.对于那些存活时间比较长的,由于回收时存活率比较高,采用标记-整理算法(由于回收方式的不同,不是一定的)

3.对于那些几乎不回收的放入方法区,方法区主要包括如下信息:被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码,常量池等。

java堆外内存

1创建线程会消耗一部分堆外内存(即除了jvm指定内存外的机器内存);

2.通过Direct ByteBuff申请的内存
原创粉丝点击