精华内容
下载资源
问答
  • java栈空间是一块线程私有的内存空间,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关。线程最基本的执行行为就是函数的调用。每次函数调用其实是通过java栈传递数据的。数据结构中的栈的特性:先进后...

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

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

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

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

    0870d2c93fdfa172b4b2b5973681a61a.png

    函数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局部变量表)

    展开全文
  • java栈java栈是一块线程私有的内存空间。如果说,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关的。线程执行的基本行为是函数调用,每次函数调用的数据都是通过Java栈传递的。java heap,java stack...

    一. java栈:

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

    java heap,java stack 与Javametaspace之间的关系:

    a80758913c1d

    00001.png

    特点:

    线程私有

    栈由一系列帧组成(因此Java栈也叫做帧栈)

    帧保存一个方法的局部变量、操作数栈、常量池指针

    每一次方法调用创建一个帧,并压栈

    1.栈的结构和组成:

    1)栈的结构:

    这是一块先进后出的数据结构,只支持出栈和入栈两种操作。在java栈中保存的主要内容是栈帧。每一次函数调用都会有一个相应的栈帧入栈,每个函数调用结束,都有一个栈帧弹出java栈。当前正在执行的函数对应的栈就是当前的帧(位于栈顶)。

    每个栈帧中,至少包含局部变量表,操作数栈和帧数据区几个部分。

    注意由于每次函数调用都会生成栈帧并占有一定的栈空间。因此如果栈空间不足,函数调用就无法进行下去。系统就会抛出StackOverflowOver栈溢出的错误。例如递归时,会有很多栈帧入栈。jvm提供了-Xss来指定线程的最大栈空间,这个参数决定了函数调用的深度。

    2)栈组成:

    栈由栈帧组成,栈帧由局部变量表,操作数栈,帧数据区组成。

    局部变量表:

    用于保存函数的参数(实参)变量和局部变量。局部变量表中的变量只在当前函数调用中有效,当函数调用结束后,随着函数栈帧的销毁,局部变量表也会随之销毁。

    操作数栈:

    栈帧的一部分,也是个先入先出的数据结构。用于计算过程的中间结果,同时作为计算过程中变量临时的存储空间。

    public static int add(int a,int b){

    int c=0;

    c=a+b;

    return c;

    }

    调用函数的过程:

    0: iconst_0 // 0压栈

    1: istore_2 // 弹出int,存放于局部变量2

    2: iload_0 // 把局部变量0压栈

    3: iload_1 // 局部变量1压栈

    4: iadd //弹出2个变量,求和,结果压栈

    5: istore_2 //弹出结果,放于局部变量2

    6: iload_2 //局部变量2压栈

    7: ireturn //返回

    a,b变量的值分别是100和98,以下是操作数栈的工作原理以及和局部变量表的关系:

    a80758913c1d

    00002.jpeg

    帧数据区:

    栈帧需要数据开支持常量池解析,正常方法返回和异常处理等

    以下的例子是个递归,没有递归的出口,会出现栈溢出,并打印递归的深度。

    public class TestStackDeep {

    private static int count=0;

    public static void recursion(long a,long b,long c){

    long e=1,f=2,g=3,h=4,i=5,k=6,q=7,x=8,y=9,z=10;

    count++;

    System.out.println(count);

    recursion(a, b, c);

    }

    public static void recursion(){

    count++;

    System.out.println(count);

    recursion();

    }

    public static void main(String[] args) {

    try {

    // recursion(0L,0L,0L);

    recursion();

    }catch (Exception e){

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

    e.fillInStackTrace();

    }

    }

    }

    影响栈空间使用的因素:

    1.阐述列表的参数多。

    2.递归的深度过深了。

    -Xss256k:

    deep of calling=568

    递归调用了568次

    -Xss512k:

    deep of calling=3030

    递归调用了568次

    Exception in thread "main" java.lang.StackOverflowError

    栈溢出,栈的空间满了。可以通过减少参数或局部变量的个数,减少栈空间的占用,达到函数多调用几次的目的。

    调用recursion(a, b, c);-Xss256k:

    最大深度716

    调用调用recursion(),-Xss256k:

    最大深度1963

    可以看到在相同的栈容量下,局部变量少的函数可以支持更深的函 数调用。

    二.栈上分配:

    栈上分配是jvm的一个优化技术,对于那些线程私有的对象,可以将它们分配在栈上,而不是堆上。栈上分配的好处是可以在函数调用后自行销毁,而不是GC介入,从而提升了系统的性能。

    栈上分配的基础是逃逸分析,逃逸分析的目的是判断对象的作用域是否有可能逃逸出函数体。

    函数alloc()内的变量b是线程私有的局部变量,

    public class OnStackTest {

    public static void alloc(){

    byte[] b=new byte[2];

    b[0]=1;

    }

    public static void main(String[] args) {

    long b=System.currentTimeMillis();

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

    alloc();

    }

    long e=System.currentTimeMillis();

    System.out.println(e-b);

    }

    }

    第一种运行方式:-server -Xmx10m -Xms10m -XX:+DoEscapeAnalysis -XX:+PrintGC

    这种方式new对象在栈上分配,gc不参与回收,因为变量仅仅在栈上分配空间,降低gc的工作量,同时防止堆上的空间被占用

    输出结果 5 效率很高。

    第二种运行方式:-server -Xmx10m -Xms10m -XX:-DoEscapeAnalysis -XX:+PrintGC

    这种方式new对象在java堆上分配,gc参与释放

    输出结果:

    ……

    [GC 3550K->478K(10240K), 0.0000977 secs]

    [GC 3550K->478K(10240K), 0.0001361 secs]

    [GC 3550K->478K(10240K), 0.0000963 secs]

    564

    GC的效率明显低于栈上分配对栈帧的销毁的效率。

    小对象(一般几十个bytes),在没有逃逸的情况下,可以直接分配在栈上

    直接分配在栈上,可以自动回收,减轻GC压力

    大对象或者逃逸对象无法栈上分配

    逃逸分析:

    下面的代码显示了一个逃逸的对象:因为代码中的User的作用域是整个Main Class,所以user对象是可以逃逸出函数体的。

    public class PartionOnStack {

    static class User{

    private int id;

    private String name;

    public User(){}

    }

    private static User user;//在这里逃逸

    public static void foo() {

    user=new User();

    user.id=1;

    user.name="sixtrees";

    }

    public static void main(String[] args) {

    foo();

    }

    }

    下面的代码展示的则是一个不能逃逸的代码段。(不能逃逸的才能栈上分配)

    public class PartionOnStack {

    class User{

    private int id;

    private String name;

    public User(){}

    }

    public void foo() {

    User user=new User();

    user.id=1;

    user.name="sixtrees";

    }

    public static void main(String[] args) {

    PartionOnStack pos=new PartionOnStack();

    pos.foo();

    }

    }

    总结:

    *小对象(一般几十个bytes),在没有逃逸的情况下,可以直接分配在栈上

    *直接分配在栈上,可以自动回收,减轻GC压力

    *大对象或者逃逸对象无法栈上分配

    展开全文
  • JAVA栈分配

    2018-06-28 23:28:03
    分配java虚拟机提供的一种优化技术,基本思想是对于那些线程私有的对象(指的是不可能被其他线程访问的对象),可以将它们打散分配上,而不是分配在堆上。分配上的好处是可以在函数调用结束后自行销毁...

    栈上分配是java虚拟机提供的一种优化技术,基本思想是对于那些线程私有的对象(指的是不可能被其他线程访问的对象),可以将它们打散分配在栈上,而不是分配在堆上。分配在栈上的好处是可以在函数调用结束后自行销毁,而不需要垃圾回收器的介入,从而提供系统的性能。

    对于大量的零散小对象,栈上分配提供了一种很好的对象分配策略,栈上分配的速度快,并且可以有效地避免垃圾回收带来的负面的影响,但由于和堆空间相比,栈空间比较小,因此对于大对象无法也不适合在栈上进行分配

    展开全文
  • java栈空间是一块线程私有的内存空间,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关。线程最基本的执行行为就是函数的调用。每次函数调用其实是通过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局部变量表)



    展开全文
  • java栈分配内存

    2021-01-03 18:56:57
    是一种java 虚拟机提供的优化技术,将私有对象打散分配上,提高性能,但无法在分配大对象 逃逸分析和标量替换是分配内存的基础 -server 开启在server模式下,才可以弃用逃逸分析 -XX:+DoEscapeAnalysis ...
  • java栈空间是一块线程私有的内存空间,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关。线程最基本的执行行为就是函数的调用。每次函数调用其实是通过java栈传递数据的。 数据结构中的栈的特性:先进...
  • 前言在java开发中,我们普遍认知中,new出的对象是直接分配到堆空间中,而实际情况并非如此,其实大家伙可以思考一下,无论方法的生命周期长与短,只要new的对象就存放在堆中,那么这样只会对jvm的gc产生一个比较大的负担而...
  • 概念对那些作用于不会逃逸出方法...Java 对象分配流程示例循环创建1000000000一个对象,阻止分配栈分配条件:开启逃逸分析 & 开启标量替换JVM 参数:弃用逃逸分析(不允许判断对象是否可以逃逸出函数体)-ser...
  • 什么是分配栈分配java虚拟机提供的一种优化技术,基本思想是对于那些线程私有的对象(指的是不可能被其他线程访问的对象),可以将它们打散分配上,而不是分配在堆上。分配上的好处是可以在函数调用...
  •   我们通过JVM内存分配可以知道JAVA中的对象都是在堆上进行分配,当对象没有被引用的时候,需要依靠GC进行回收内存,如果对象数量较多的时候,会给GC带来较大压力,也间接影响了应用的性能。为了减少临时对象在堆...
  • Java栈

    2012-09-04 09:48:45
    当执行一个新线程的时候,Java虚拟机会为这个线程分配对应的Java栈,可以说Java栈就是这个线程的临时数据存储区,如果有多个方法那么将存在多个Java栈,这些Java栈与这些方法一一对应。 一个方法也是一个线程,无论是...
  • Java对象分配

    千次阅读 2019-09-25 14:46:11
    在学习Java的过程中,很多喜欢说new出来的对象分配一定在对上;其实不能这么说,只能说大部分对象分配是在对上。通过对象的分配过程分析,除了堆以外,还有两个地方可以存放对...
  • Java常见面试题—栈分配与TLAB

    万次阅读 多人点赞 2017-08-29 22:13:17
    在学习Java的过程中,一般认为new出来的对象都是被分配在堆上的,其实这个结论不完全正确,因为是大部分new出来的对象被分配在堆上,而不是全部。通过对Java对象分配的过程分析,可以知道有另外两个地方也是可以存放...
  • Java内存分配:堆和

    2019-03-21 00:39:50
    Java中的内存分配主要...函数中定义的一些基本类型的变量数据和对象的引用地址都在函数的内存中分配,当在一段代码块定义一个变量时,Java就在中为这个变量分配内存空间,当该变量退出作用域后,Java会自动释...
  • Java内存分配堆和

    2016-07-10 10:00:29
    Java堆和 内存,牵涉编译原理,程序运行的时候操作系统如何合理分配内存,如果运行之前就确定所占内存大小,变量的生存期 Java中将基本类型 声明对象的引用保存在站中,将数组尤其是可变大小数组 和对象保存在堆中...
  • java堆与 java String分配内存空间(详解)   重点: 1、当比较包装类里面的数值是否相等时,用equals()方法; 2、当测试两个包装类的引用是否指向同一个对象时,用==。 可以这样理解吗?  2.1、 中的...
  • Java中的分配

    2017-02-18 23:50:00
    分配java虚拟机提供的一种优化技术,基本思想是对于那些线程私有的对象(指的是不可能被其他线程访问的对象),可以将它们打散分配上,而不是分配在堆上。分配上的好处是可以在函数调用结束后自行销毁...
  • Java内存分配以及和堆的区别 Java程序为了提高程序的效率,就对数据进行了不同的空间分配。 具体的是划分为了5个内存空间: **:**存放的是局部变量 **堆:**存放的是所有new出来的东西 方法区:(暂时不说) ...
  • Java栈异常

    2021-03-27 11:24:15
    “深入理解Java虚拟机”提出的两种异常: 1、如果线程请求的深度大于虚拟机所允许的深度,将抛出...其实上面的2种异常说明了2个事情:虚拟机分配的空间有限、系统分配给虚拟机的空间有限。 比如机子有
  • java栈溢出

    2019-03-04 16:51:26
     在java虚拟机规范中,虚拟机和本地方法都会出现StackOverflowError和OutofMemoryError,程序计数器是java虚拟机中唯一一块不会产生error的内存区域。 一、StackOverflowError(溢出) StackOverflowError...
  • 当在一段代码块定义一个变量时,Java就在中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。堆内存用来存放由new创建的对象和数组。在...
  • Java内存分配之堆、和常量池
  • 分配主要是指在Java程序的执行过程中,在方法体中声明的变量以及创建的对象,将直接从该线程所使用的分配空间。 一般而言,创建对象都是从堆中来分配的,这里是指在上来分配空间给新创建的对象 什么是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,405
精华内容 5,362
关键字:

java栈分配

java 订阅