java内存模型

java虚拟机栈:

JVM的基础架构就是虚拟机栈,即程序指令的每一个操作都要经过入栈和出栈操作。

2.JVM的虚拟机栈位于RAM里面,通过栈指针来访问可以访问处理器,访问速度仅次于寄存器。

jav虚拟机栈的缺点:

1.需要预先去生成相应的内存空间,当程序运行时,java虚拟机必须知道被存储在栈内的所有数据的确切大小和生命周期,所以,虚拟机栈缺乏灵活性。所以,虚拟机栈主要被用来存放一些基本类型的数据、对象的引用。而程序内部数量庞大的Java对象没有放在虚拟机栈里面。

2.速度比较

寄存器>虚拟机栈>虚拟机堆

3.共享特性

虚拟机栈有一个特殊的特性,就是在栈里面的数据可以共享。假设同时定义:int a=1;int b=1; 第一条语句,首先会创建一个变量为a的引用,然后查询栈内是否存在1这个值,如果没有找到,就将1放进了。然后将a指向1。接下来处理第 二条语句,在创建完 b 的引用变量后,因为在栈内已经有 1 这个值,便将 b 直接指向 1。这样, 就出现了 a 与 b 同时均指向 l 的情况。这时,如果存在第三条语句,它针对 a 再次定义为 a=4, 那么编译器会重新搜索棋内是否有 4 值,如果没有,则将 4 存放进来,并令 a 指向 4,如果已 经有了,则直接将 a指向这个地址,因此 a 值的改变不会影响到 b 的值1。要注意这种数据的共 享与两个对象的引用同时指向一个对象的这种共享的方式存在明显的不同,因为这种情况 a 的 修改井不会影响到 b,它是由虚拟机完成的,这样的做法有利于节省空间。而一个对象引用变 量修改了这个对象的内部状态,会影响到另一个对象引用变量。

4.虚拟机栈也是线程私有的内存空间,它和JAVA线程在同一时间创建,它保存方法的局部变量、部分结果,并参与方法的调用和返回。

5.栈异常:

StackoverFlowError:如果线程在计算过程中,如果请求的深度大于栈的深度,则程序抛出StackoverFlowError异常。

OutOfMemoryError:如果java栈是可以扩展的,而扩展过程中没有足够的空间来支持,则抛出OutOfMemoryError异常。可以用-XSS来设置虚拟机栈的大小。

StackoverFlowError异常:

package javaapplication1;

 

/**

*

* @author xy7

*/

public class Stack {

private int count = 0;

public void recursion(){

count++;

recursion();

}

public void testStack(){

try {

recursion();

} catch (Exception e) {

System.out.println("deep of stack;"+count);

e.printStackTrace();

}

}

public static void main(String[] args) {

Stack test = new Stack();

test.testStack();

}

}

虚拟机栈的内部结构:

1.在虚拟机栈运行时,有一种叫做栈帧的数据结构保存上下文数据。

2.栈帧的组成

1.存放了局部变量表,操作数栈,动态链接方法和返回地址信息等。每一个方法的调用都伴随者出栈和入栈方法的返回则表示战 帧的出战操作。 如果方法调用时,方法的参数和局部变量相对较多,那么找帧中的局部变量表 就会比较大,梳,,班会不断膨胀以满足方法调用所需传递的信息增大需求。因此,单个方法调用 所需的战空间也会比较多。

2.组成详细:局部变量区、操作数栈和帧数据区

 

局部变量区被定义为一个从 0 开始的数字数组, byte、 short、 char 在存储前被转换为 int, boolean 也被转换为 int, 0 表示 false,非 0 表示 true, long 和 double 则占据两个字长。注意, 局部变量区是通过数组下标访问的。

操作数栈也被组织为一个数字数组,但不同于局部变量区,它不是通过数组下标访问的,而是通过拢的 Push 和 Pop1操作,前一个操作 Push 进的数据可以被下一个操作 Pop 出来使用。

帧数据区这部分的作用主要有三点。

· 解析常量池里面的数据。

· 方法执行完后处理方法返回,恢复调用方现场。

· 方法执行过程中抛出异常时的异常处理,存储在一个异常衰,当出现异常时虚拟机查找 相应的异常表看是否有对应的 Catch 语句,如果没有就抛出异常终止这个方法调用。

函数嵌套调用的次数由栈的大小决定。一般来说,栈越大,函数嵌套调用次数越多。对一 个函数而言,它的参数越多, 内部局部变量越多,它的技帧就越大,其嵌套调用次数就会减少。

在栈帧中,与性能调优关系最为密切的部分就是前面提到的局部变量区。局部变量区被用 于存放方法的参数和进行方法内部的引用。局部变量区以“字”为单位进行内存的划分, 一个 字为 32 位长度。对于 long 和 double 型的变量,则占用 2 个字,其余类型使用 1 个字。在方法 执行时,虚拟机使用局部变量区完成方法的传递,对于非静态(static)方法, 虚拟机还会将当 前对象(this)作为参数通过局部变量区传递给当前方法。

本地方法栈(native method stacks):

本地方法找(Native Method Stacks)和 Java 虚拟机栈的功能很相似Java 虚拟机栈用于管 理 Java 函数的调用,而本地方法枝用于管理本地方法的调用。本地方法并不是用 Java 实现的, 而是使用 C 实现的。当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟 机限制的世界,本地方法可以通过本地方法接口来访问虚拟机内部的运行时数据区,但不止于 此,它还可以做任何它想做的事情。 比如,它甚至可以直接使用本地处理器中的寄存器,或者 直接从本地内存的堆中分配任意数量的内存。总之,它和虚拟机拥有同样的权限(或者说能力)。

Java堆(stacks):

1.是虚拟机规范的一种内存池,也存在于RAM中,用于存放所有的java对象。堆是一个运行时数据区,类的对象从中分配空间,这些对象通过 New 关键字建立,它们不需要 程序代码来显式地释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生 存周期也不需要事先告诉编译器。由于它是在运行时动态分配内存的, Java 的垃圾收集器会自 动收走那些不再使用的数据。但缺点是,由于要在运行时动态分配内存,所以数据访问速度较 慢。大多数的虚拟机里, Java 中的对象和数组都存放在堆中。

堆不同于械的优势是,虚拟机不需要知道要从堆内分配多少存储区域,也不必知道存储的 数据在堆内需要存活多长时间。因此,在堆内分配存储相较于梳来说,有很大的灵活性。当你 需要创建一个对象的时候,只需要引用 New 关键字写一行简单的代码,当执行这行代码时,会 自动在堆内进行存储分配。当然,为这种灵活性必须要付出相应的代价,即用堆进行存储分配 比用技进行存储需要更多的时间。

Java 堆区在 JVM 启动的时候即被创建,它只要求逻辑上是连续的,在物理空间上可以是不 连续。所有的线程共享 Java 堆,在这里可以划分钱程私有的缓冲区 (Thread Local Allocation Buffer, TLAB) 。

如前所述, Java 堆区是一块用于存储对象实例的内存区,同时也是 GC (Garbage Collection, 垃圾收集器〉执行垃圾回收的重点区域。正是因为 Java 堆区是 GC 的重点回收区域,所以 GC 极有可能会在大内存的使用和频繁进行垃圾回收过程上成为系统性能瓶颈。为了解决这个问题, 川岛4 的设计者们开始考虑是否一定需要将对象实例存储到 Java 堆区内。基于 OpenJDK深度定 制的 TaobaoJVM,其中创新的 GCJVM (GC invisible heap)技术实现了 off-heap,即将生命周期 较长的 Java 对象从 heap 中移到 heap 之外,并且 GC 不能管理 GCIH 内部的 Java 对象,以此达

到降低 GC 的回收频率和提升 GC 的回收效率的目的。

除此之外,逃逸分析(图 2-3)与枝上分配这样的优化技术同样也是降低 GC 回收频率和提 升 GC 回收效率的有效方式。这样一来, Java 堆区就不再是 Java 对象内存分配的唯一选择了。 目前主流的垃圾收集算法是按代(Generation)收集,即按照对象的生存时间分为年轻代和老年 代。年轻代又进一步被划分为 Eden 区、 From Survivor 区和 To Survivor 区, 主要是为了垃圾回 收用途。逃逸分析英文全名是 Escape Analysis。在计算机语言编译器优化原理中,逃逸分析是指分 析指针动态范围的方法,它同编译器优化原理的指针分析和外形分析相关联。 计算机软件方面, 逃逸分析指的是计算机语言编译器语言优化管理中,分析指针动态范围的方法。通俗点讲,如 果一个对象的指针被多个方法或线程引用时,那我们可以称这个指针发生了逃逸。 Java 语言也 有逃逸情况存在,

 

 

Java7 开始支持对象的技分配和逃逸分析机制。这样的机制除了能将堆分配对象变成枝分配 对象以外,逃逸分析还有其他两个优化应用。

·同步消除。线程同步的代价是相当高的,同步的后果是降低并发性和性能。逃逸分析可 以判断出某个对象是否始终只被一个线程访问,如果只被一个线程访问,那么对该对象 的同步操作就可以转化成没有同步保护的操作,这样就能大大提高并发性和性能。 · 矢量替代。逃逸分析方法如果发现对象的内存存储结构不需要连续进行的话,就可以将 对象的部分甚至全部都保存在 CPU 寄存器内,这样能大大加快访问速度。

方法区:

主要保存的信息是类的元数据,方法区与对空间类似,它也是被JVM中所有线程共享的区域。方法区中最为重要的是类的类型信息、常量池、域信息、方法信息。

 

 

 

 

内存模型图

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值