java栈帧还是需要一些数据支持常量池的解析、正常方法的返回和异常的处理。大部分的java字节码指令需要进行常量池的访问,在栈帧数据区中保存着访问常量池的指针,方便程序访问java常量池。如下图所示:

当函数返回或者程序出现异常的时候,jvm虚拟机必须恢复调用者函数的栈帧,并且让调用者函数继续执行。什么意思呢?举一个通俗的例子:

a()调用b()当b()返回的时候肯定继续让a()继续执行对吧。b()抛出异常的时候a()肯定也需要处理对吧。

对于异常的处理,jvm是如何处理的呢?虚拟机肯定必须有一个异常处理表,方便发生异常的时候找到处理异常的代码,方便程序继续运转,因此异常处理表Exception table也是帧数据区中很重要的一部分。怎么获取Exception table
中的信息呢操作如下:

执行命令

javap -verbose命令输出它的字节码(不懂这个命令的可以javap -help查看)

from   to  target type

0     8     19   any

表示在字节码
0-8个字节可能抛出异常,如果遇到异常,则跳转到字节码偏移量19出执行,当方法抛出异常的时候,虚拟机就会查找类似的异常表进行处理,如果无法找到异常表中对应的信息,则会结束当前程序的调用,返回调用函数,并在调用函数中抛出这个异常信息,并查找函数的异常表进行处理。

通俗易懂的说:

a()调用b()  当b()方法中有异常的时候,b()中处理了则继续执行,程序没有处理也就没有异常表信息直接抛异常到a()方法,b()栈移除,a()处理了继续流转,没有处理直接异常抛出。

1.1.1. 栈上分配

栈上分配是java虚拟机提供的一种优化技术,基本思想是,对于那些线程私有对象(不可能被其他线程访问的对象),可以将他们打散分配到栈上,而不是分配在堆上,(是不是很毁三观啊,是不是以前认识的都不对啊白着急)。分配在栈上面的好处函数调用完成后直接自杀销毁,而不需要垃圾回收机制介入回收,所以这样对于性能的提升还是蛮有帮助的。

栈上分配有一个前提条件:开启逃逸分析(必须否则不会栈上分配),逃逸分析的目的就是判断对象的作用域是否有可能逃逸出函数体。如下代码:

private static Useruser;

public static void alloc(){

user=new User();

user.setId(5);

user.setName("springok");

}

对象User user 因为是static  方法中因此可以被任何线程访问到。所以属于逃逸对象。

下面的代码显示了一个非逃逸对象:

public static void alloc(){

User user;

user=new User();

user.setId(5);

user.setName("springok");

}

因为不可以被其他的线程访问到。对象user以局部变量形式存在,该对象没有被返回出去,也没有任何地方可以访问到在其他的方法中,因此是非逃逸的,所以虚拟机可能将user分配在栈上。下面的代码对其结论进行证明:

public static void alloc() {

User
user = new User();

user.setId(5);

user.setName("springok");

}

public static void main(String[]args) {

long begin = System.currentTimeMillis();

for (int i = 0;i < 100000000;i++)
{

alloc();

}

long end = System.currentTimeMillis();

System.out.println(end-begin);

}

上面代码进行一亿次调用进行对象的创建,累计分配的内存可能达到了1.5G,如果堆空间小于这个1.5G肯定会GC垃圾回收,所以我们开启垃圾回收的参数。

运行配置的参数如下:

-server -Xmx10m -Xms10m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:+EliminateAllocations

jvm参数使用说明:

-server  因为在server模式才能启用逃逸分析。

-XX:+DoEscapeAnalysis
启用逃逸分析

-Xmx10m 堆空间最大10MB.如果对象在堆上创建肯定会GC垃圾回收的。

-XX:+PrintGC 打印GC日志。

-XX:+EliminateAllocations
开启标量替换默认就是开启的,允许对象打散分配到栈上。

user对象拥有的id和name属性将会被视为独立的局部变量分配。

-XX:-UseTLAB 关闭TLAB

程序执行后完整的打印如下:

5

可以看到没有任何形式的GC输出,程序执行完毕了。说明user对象确实在分配过程被优化了。

如果关闭逃逸分析或者标量替换任意一个,再次执行程序,就会看到大量的GC日志如下:

[GC 3226K->474K(9920K), 0.0001595 secs]

[GC 3226K->474K(9920K), 0.0001488 secs]

[GC 3226K->474K(9920K), 0.0001726 secs]

[GC 3226K->474K(9920K), 0.0001614 secs]

1556

代码侧面印证了结论的正确性。

第一说明了上面的结论,栈上分配依赖逃逸分析和标量替换的实现,第二确实开启了对象被分配在栈上,而不是堆上。因为在堆上肯定会GC垃圾回收的。

对于大量零散的小对象,栈上分配提供了很好的优化策略,栈上分配速度快,可以避免垃圾回收。但由于和堆相比栈的空间小,因此大对象不适合在栈上分配。

java虚拟机 jvm 栈数据区的更多相关文章

  1. Java虚拟机运行时数据区

    运行时数据区程序计数器Java虚拟机栈本地方法栈Java堆(GC堆)方法区运行时常量池 运行时数据区 Java虚拟机在运行Java程序时,会将它所管理的内存划分为若干个内存区域.这些数据区域有各自的用 ...

  2. 面试常问的 Java 虚拟机运行时数据区

    写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...

  3. Java 虚拟机运行时数据区

    写在前面 本文描述的有关于 JVM 的运行时数据区是基于 HotSpot 虚拟机. 概述 JVM 在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以 ...

  4. 《深入理解Java虚拟机》(二)Java虚拟机运行时数据区

    Java虚拟机运行时数据区 详解 2.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第二章 ,为了整理思路,简单记录一下,方便后期查阅. 2.2 运行时数据区域 Java虚拟机 ...

  5. 【深入理解Java虚拟机】Java虚拟机运行时数据区

    Java虚拟机运行时数据区 线程私有 程序计数器 1.当前线程所执行的字节码的行号指示器. 2.唯一不会发生OutOfMemoryError的区域 3.如果执行的是java方法,计数器值为虚拟机字节码 ...

  6. 【JVM从小白学成大佬】2.Java虚拟机运行时数据区

    目录 1.运行时数据区介绍 2.堆(Heap) 是否可能有两个对象共用一段内存的事故? 3.方法区(Method Area) 4.程序计数器(Program Counter Register) 5.虚 ...

  7. 【JVM学习】2.Java虚拟机运行时数据区

    来源: 公众号: 猿人谷 这里我们先说句题外话,相信大家在面试中经常被问到介绍Java内存模型,我在面试别人时也会经常问这个问题.但是,往往都会令我比较尴尬,我还话音未落,面试者就会"背诵& ...

  8. Java 虚拟机运行时数据区详解

    本文摘自深入理解 Java 虚拟机第三版 概述 Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟 ...

  9. 笔记:Java虚拟机运行时数据区

    Java虚拟机在执行Java程序的过程中会把它管的内存划分为以下若干个不同的区域: 1.程序计数器 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器:由于Java虚拟机的 ...

随机推荐

  1. [USACO 08JAN]Haybale Guessing

    Description The cows, who always have an inferiority complex about their intelligence, have a new gu ...

  2. [ZJOI2008]瞭望塔

    题目描述 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安. 我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), ...

  3. codefroces 55D Beautiful numbers

    [Description] 美丽数是指能被它的每一位非0的数字整除的正整数. [Input] 包含若干组数据,每组数据一行两个数n,m,表示求[n,m]之间的美丽数的个数. [output] 对于每组 ...

  4. SpringBoot学习之基础篇

    在前面的博文中,已经演示过springboot与Mybatis集成的实例,本篇再来探讨一下SpringBoot的基础.  一.关于SpringBoot SpringBoot可以基于Spring轻松创建 ...

  5. 我在 B 站学习深度学习(生动形象,跃然纸上)

    我在 B 站学习深度学习(生动形象,跃然纸上) 视频地址:https://www.bilibili.com/video/av16577449/ tensorflow123 http://tensorf ...

  6. ionic 禁用 手势 滑动返回

    $ionicConfigProvider.views.swipeBackEnabled(false); 在 应用的 config里面 配置下 上面的那句话 就OK了.

  7. js页面刷新跳转的几种方式及区别

    跳转常用方法: window.location.href="index.php"; window.history.back(-1);//类似于按钮,参数是负几,就后退几次. win ...

  8. git报错:'fatal:remote origin already exists

    git报错:'fatal:remote origin already exists'怎么处理?附上git常用操作以及说明.   git添加远程库的时候有可能出现如下的错误, 怎么解决? 只要两步: 1 ...

  9. 关于ES7中的async/await在客户端和服务端上的实践

    一.前言 在项目中经常遇到处理异步请求的情况,面对层层的嵌套,回调显示那么苍白无力: async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解决方案,既然这样就用上吧. 二.配 ...

  10. 1-学习GPRS_Air202(Air202开发板介绍)

    记得自己第一次实现远程通信是在学校里用SIM900A实现的,随着WIFI模块的普及自己就开始用WIFI模块了,当然WIFI模块已经用的很... WIFI模块要想实现远程控制必须连接路由器,其实在做王哥 ...