深入理解JVM(深入理解jvm第四版pdf百度云)

  本篇文章为你整理了深入理解JVM(深入理解jvm第四版pdf百度云)的详细内容,包含有深入理解jvm第四版 深入理解jvm第四版pdf百度云 深入理解jvm第四版pdf 深入理解jvm第三版pdf 深入理解JVM,希望能帮助你了解 深入理解JVM。

  1.java虚拟机栈

  

   1. Java虚拟机栈也是线程私有的,它的生命周期与线程相同(随线程而生,随线程而灭)

   2. 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;

   如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常;

   (当前大部分JVM都可以动态扩展,只不过JVM规范也允许固定长度的虚拟机栈)

   3. Java虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的同时会创建一个栈帧。

   对于我们来说,主要关注的stack栈内存,就是虚拟机栈中局部变量表部分。
 

  2.栈帧(Stack Frame)

   栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。它是虚拟机运行时数据区中的java虚拟机栈的栈元素。

   栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。

   每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机里面从入栈到出栈的过程。

   注意:

  

在编译程序代码的时候,栈帧中需要多大的局部变量表内存,多深的操作数栈都已经完全确定了。

 

  因此一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。

 

   栈结构图如下:

   注意:

   在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧,与这个栈帧相关联的方法称为当前方法。

   执行引擎运行的所有字节码指令都只针对当前栈帧进行操作。

  3.局部变量表

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

   并且在Java编译为Class文件时,就已经确定了该方法所需要分配的局部变量表的最大容量。

   2.局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)「String是引用类型」,
 

   对象引用(reference类型) 和 returnAddress类型(它指向了一条字节码指令的地址)

   注意:

   很多人说:基本数据和对象引用存储在栈中。

   当然这种说法虽然是正确的,但是很不严谨,只能说这种说法针对的是局部变量。

   局部变量存储在局部变量表中,随着线程而生,线程而灭。并且线程间数据不共享。

   但是,如果是成员变量,或者定义在方法外对象的引用,它们存储在堆中。

   因为在堆中,是线程共享数据的,并且栈帧里的命名就已经清楚的划分了界限 : 局部变量表!

  4.变量槽(Variable Slot)

   局部变量表的容量以变量槽为最小单位,每个变量槽都可以存储32位长度的内存空间,例如boolean、byte、char、short、int、float、reference。

   对于64位长度的数据类型(long,double),虚拟机会以高位对齐方式为其分配两个连续的Slot空间,也就是相当于把一次long和double数据类型读写分割成为两次32位读写。

   扩展知识点:

  

Slot复用 

 

  为了尽可能节省栈帧空间,局部变量表中的Slot是可以重用的,

  也就是说当PC计数器的指令指已经超出了某个变量的作用域(执行完毕),

  那这个变量对应的Slot就可以交给其他变量使用。

  优点 : 节省栈帧空间。

  缺点 : 影响到系统的垃圾收集行为。

  (如大方法占用较多的Slot,执行完该方法的作用域后没有对Slot赋值或者清空设置null值,垃圾回收器便不能及时的回收该内存。)

 

  5.reference(对象实例的引用)

   我的理解是:一个超链接

   一般来说,虚拟机都能从引用中直接或者间接的查找到对象的以下两点 :

   a.在Java堆中的数据存放的起始地址索引。

   b.所属数据类型在方法区中的存储类型。

   例如:我们在创建一个Student对象时的数据存储结构:

  6.动态连接

   每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,

   持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。

   在类加载阶段中的解析阶段会将符号引用转为直接引用,这种转化也称为静态解析。

   另外的一部分将在每一次运行时期转化为直接引用。这部分称为动态连接。

   这里简单提一下动态连接的概念,后面在详细讲解.

  7.方法出口

   当一个方法开始执行后,只有2种方式可以退出这个方法 :

   方法返回指令 : 执行引擎遇到一个方法返回的字节码指令,这时候有可能会有返回值传递给上层的方法调用者,这种退出方式称为正常完成出口。

   异常退出 : 在方法执行过程中遇到了异常,并且没有处理这个异常,就会导致方法退出。

   无论采用任何退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息。

   一般来说,方法正常退出时,调用者的PC计数器的值可以作为返回地址,栈帧中会保存这个计数器值。

   而方法异常退出时,返回地址是要通过异常处理器表来确定的,栈帧中一般不会保存这部分信息。

  8.实战案例

   如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常

  

 1 package com.wfd360.demo01;

 

   3 /**

   4 * @Copyright (C)

   5 * @Author: LI DONG PING

   6 * @Date: 2019-07-15 17:17

   7 * @Description: 栈内存溢出测试

   8 * p

   9 * 测试代码设计思路

  10 * 修改默认堆栈大小后,利用递归调用一个方法,达到栈深度过大的异常目的,同时在递归调用过程中记录调用此次,得出最大深度的数据

  11 * jvm参数

  12 * -Xss 180k:设置每个线程的堆栈大小(最小180k),默认是1M

  13 */

  14 public class TestStackOverflowErrorDemo {

  15 //栈深度统计值

  16 private int stackLength = 1;

  18 /**

  19 * 递归方法,导致栈深度过大异常

  20 */

  21 public void stackLeak() {

  22 stackLength++;

  23 stackLeak();

  26 /**

  27 * 启动方法

  28 * 测试结果:当-Xss 180k为180k时,stackLength~=1544,随着-Xss参数变大时stackLength值随之变大

  29 * @param args

  30 */

  31 public static void main(String[] args) {

  32 TestStackOverflowErrorDemo demo = new TestStackOverflowErrorDemo();

  33 try {

  34 demo.stackLeak();

  35 } catch (Throwable e) {

  36 System.out.println("当前栈深度:stackLength=" + demo.stackLength);

  37 e.printStackTrace();

  40 }

 

  View Code

   测试结果:

  

   完美!

  

  以上就是深入理解JVM(深入理解jvm第四版pdf百度云)的详细内容,想要了解更多 深入理解JVM的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: