java虚拟机 jvm 出入java栈 栈空间内存分配

java栈空间是一块线程私有的内存空间,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关。线程最基本的执行行为就是函数的调用。每次函数调用其实是通过java栈传递数据的。

数据结构中的栈的特性:先进后出,后进先出。FIFO.

java内存中的栈跟数据结构中的特性相似也是FIFO.但是只支持进栈和出栈操作。

java栈中保存的主要内容是栈帧。每一次函数调用都会有对应的栈帧被压进去java栈,执行完毕的时候被弹出java栈。如下图所示。

函数1对应栈帧1,函数2对应栈帧2.函数3对应栈帧3.以此类推。

函数1调用函数2,函数2调用函数3,函数3调用函数4,以此类推。

函数1被调用的时候栈帧1入栈,函数2被调用的时候栈帧2入栈,以此类推。

所以最后被调用的函数在栈顶,也是最先被弹出栈的。

每一个栈帧保存着函数的局部变量、中间运算结果等数据。

函数返回的时候,栈帧从java栈弹出。什么时候函数返回呢?两种情况:

1.正常的return的时候。

2.程序抛出异常。

在一个栈帧内,至少包含局部变量表、操作数帧和帧数据区几部分。

思考的问题:没一次函数调用生成栈帧,从而肯定会占用一定的栈空间。所以栈空间内存不足的时候,函数调用无法进行。当请求的栈深度大于最大栈深度的时候系统会抛出StackOverflowError异常。(内存溢出会在以后的章节深入的讲解和汇总)

java虚拟机制定线程的最大栈空间参数为-Xss,这个参数决定了函数调用的最大深度。

下面一段代码说明,是一个没有出口的递归。这段代码可能会栈溢出错误。如下所示:

private static int count=0;
public static void recursion(){
count++;
recursion();
}
public static void main(String[] args) {
try {
recursion();
} catch (Exception e) {
System.out.println("deep of calling="+count);
e.printStackTrace();
}
}

使用参数-Xss128K执行代码,结果如下:

deep of calling=2020
Exception in thread "main" java.lang.StackOverflowError
at cn.xhgg.test.TestStackDeep.recursion(TestStackDeep.java:6)

使用参数-Xss256K执行代码,结果如下:

count=3665
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)

两次内存不同对比:

内存增大很明显调用次数增加了。

结论:

函数嵌套的层数很大程度上有栈的大小决定的。栈越大,函数调用的次数就越多。

什么因素影响函数在栈中内存大大小呢?下一个章节介绍(java虚拟机jvm局部变量表)

时间: 2024-10-02 17:55:13

java虚拟机 jvm 出入java栈 栈空间内存分配的相关文章

深入理解Java虚拟机:JVM高级特性与最佳实践

目 录 [ - ] <深入理解Java虚拟机:JVM高级特性与最佳实践>前言 <深入理解Java虚拟机:JVM高级特性与最佳实践>内容特色 <深入理解Java虚拟机:JVM高级特性与最佳实践>目录 第1章 走近Java 1.1 概述 1.2 Java技术体系 1.3 Java发展史 1.4 展望Java技术的未来 1.4.1 模块化 1.4.2 混合语言 1.4.3 多核并行 1.4.4 进一步丰富语法 1.4.5 64位虚拟机 1.5 实战:自己编译JDK 1.5.1

c++的问题-堆空间内存分配,关于首地址处记录分配内存的大小的问题

问题描述 堆空间内存分配,关于首地址处记录分配内存的大小的问题 堆空间内存分配时,首地址处记录分配内存的大小会不会占用内存空间. 大小记录在首地址处,如果占用了首地址的内存空间,首地址又怎么能用来存储数据了呢. 比如 char *a = new char; 分配的一个字节空间需要用来记录分配内存的大小,再拿来存字节'a',那么存储的大小信息不就丢失了吗? 求解答,万分感谢! 解决方案 a是在栈上,只不过他申请的空间是在堆上,记录分配内存的大小和地址是在页的首地址,不会用来存放a所对应的数据,a申

java虚拟机 jvm 栈数据区

java栈帧还是需要一些数据支持常量池的解析.正常方法的返回和异常的处理.大部分的java字节码指令需要进行常量池的访问,在栈帧数据区中保存着访问常量池的指针,方便程序访问java常量池.如下图所示:   当函数返回或者程序出现异常的时候,jvm虚拟机必须恢复调用者函数的栈帧,并且让调用者函数继续执行.什么意思呢?举一个通俗的例子: a()调用b()当b()返回的时候肯定继续让a()继续执行对吧.b()抛出异常的时候a()肯定也需要处理对吧. 对于异常的处理,jvm是如何处理的呢?虚拟机肯定必须

了解Java虚拟机JVM的基本结构及JVM的内存溢出方式_java

JVM内部结构图 Java虚拟机主要分为五个区域:方法区.堆.Java栈.PC寄存器.本地方法栈.下面 来看一些关于JVM结构的重要问题. 1.哪些区域是共享的?哪些是私有的? Java栈.本地方法栈.程序计数器是随用户线程的启动和结束而建立和销毁的, 每个线程都有独立的这些区域.而方法区.堆是被整个JVM进程中的所有线程共享的. 2.方法区保存什么?会被回收吗? 方法区不是只保存的方法信息和代码,同时在一块叫做运行时常量池的子区域还 保存了Class文件中常量表中的各种符号引用,以及翻译出来的

java虚拟机 jvm 局部变量表实战

java局部变量表是栈帧重要组中部分之一.他主要保存函数的参数以及局部的变量信息.局部变量表中的变量作用域是当前调用的函数.函数调用结束后,随着函数栈帧的销毁.局部变量表也会随之销毁,释放空间. 由于局部变量表存在栈帧中.所以,如果函数参数和局部变量比较多,会使的局部变量表膨胀,每一次调用会占用更多的栈空间.最终结局就是栈空间内存一定的情况下调用的次数减少. 1.1.1. 局部变量表变量影响 下面的代码演示在栈空间内存一定的情况下,参数以及局部变量的大小对函数调用次数的影响.第一个函数recur

Java虚拟机JVM性能优化(一):JVM知识总结_java

Java应用程序是运行在JVM上的,但是你对JVM技术了解吗?这篇文章(这个系列的第一部分)讲述了经典Java虚拟机是怎么样工作的,例如:Java一次编写的利弊,跨平台引擎,垃圾回收基础知识,经典的GC算法和编译优化.之后的文章会讲JVM性能优化,包括最新的JVM设计--支持当今高并发Java应用的性能和扩展. 如果你是一个开发人员,你肯定遇到过这样的特殊感觉,你突然灵光一现,所有的思路连接起来了,你能以一个新的视角来回想起你以前的想法.我个人很喜欢学习新知识带来的这种感觉.我已经有过很多次这样

Java虚拟机jvm关于内存的设置与调优

JVM内存的设置的原理 默认的java虚拟机的大小比较小,在对大数据进行处理时java就会报错:java.lang.OutOfMemoryError. 设置jvm内存的方法,对于单独的.class,可以用下面的方法对Test运行时的jvm内存进行设置. java -Xms64m -Xmx256m Test -Xms是设置内存初始化的大小 -Xmx是设置最大能够使用内存的大小(最好不要超过物理内存大小) 在weblogic中,可以在startweblogic.cmd中对每个domain虚拟内存的大

Java虚拟机JVM性能优化(二):编译器_java

本文将是JVM 性能优化系列的第二篇文章(第一篇:传送门),Java 编译器将是本文讨论的核心内容. 本文中,作者(Eva Andreasson)首先介绍了不同种类的编译器,并对客户端编译,服务器端编译器和多层编译的运行性能进行了对比.然后,在文章的最后介绍了几种常见的JVM优化方法,如死代码消除,代码嵌入以及循环体优化. Java最引以为豪的特性"平台独立性"正是源于Java编译器.软件开发人员尽其所能写出最好的java应用程序,紧接着后台运行的编译器产生高效的基于目标平台的可执行代

初学者对于java继承、多态,子类对象的内存分配的一些问题,百度了好多,但感觉没有系统的,在此提问,希望前辈们传到授业解惑

问题描述 由于是初学者,所以有些表述可能有误,都只是自己的一些理解.我是纯初学者,看过两个星期的C++,之前也学过C.感觉看C++的时候,更容易去理解C++中的面向对象技术的实现,但看JAVA的时候,可能隔着一层虚拟机,有些实现很难理解.第一个问题:我了解到一个对象里面,隐含了一个引用this,可以用this来特别地引用本对象的成员或者函数,然后还有一个super关键字,书上说这个关键字不是一个引用,但怎么看都感觉这个super是一个指向本对象的父类类型的引用.我想问这个super到底是什么,如