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. [自用]数论和组合计数类数学相关(定理&证明&板子)

    0 写在前面 本文受 NaVi_Awson 的启发,甚至一些地方直接引用,在此说明. 1 数论 1.0 gcd 1.0.0 gcd $gcd(a,b) = gcd(b,a\;mod\;b)$ 证明:设 ...

  2. [HNOI 2017]礼物

    Description 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手 环,一个留给自己,一个送给她.每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度.但是在 ...

  3. [SDOI2008]Cave 洞穴勘测

    题目描述 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假 ...

  4. codeforces 842D Vitya and Strange Lesson

    题目大意: 定义mex数为数组中第一个没有出现的非负整数.有m个操作,每个操作有一个x,将数组中所有的元素都异或x,然后询问当前的mex Input First line contains two i ...

  5. HDU - 3037:Saving Beans

    #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #in ...

  6. hdu 5478 (数论)

    ⋅n+b1⋅n−k2+1 = 0 (mod C)(n = 1, 2, 3, ...)  (1<=a, b <C) 1.  当n = 1时, a^(k1+b1) + b = 0 ( mod ...

  7. Linux设备树语法详解【转】

    转自:http://www.cnblogs.com/xiaojiang1025/p/6131381.html 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备 ...

  8. C语言程序设计第一次作业(2017.10.10完成)

    一:程序框图以及正确运行结果: (1)给出圆半径,得出圆面积: ①程序框图如下: ②测试图如下: 经过测试 ,输入半径2能得出正确结果.多次测试,输入不同值,均得出正确结果,证明稳定性. ③实验分析: ...

  9. axios的兼容性处理

    一.简介 看看官网的简介: "Promise based HTTP client for the browser and node.js" 译:基于 Promise 的 HTTP ...

  10. pm2进阶使用

    启用集群模式 只需要在启动应用时带上i参数 pm2 start app.js -i max max:意味着PM2将自动检测可用的CPU数量和运行多个进程可以在负载均衡模式(但是不推荐使用) 或者使用j ...