网站建设创业书,品牌建设对企业发展的重要性,北京知名互联网公司排名,各大门户网站怎么做推广虚拟机栈的背景
由于跨平台性的设计#xff0c;java的指令都是根据栈来设计的。不同平台CPU架构不同#xff0c;所以不能设计为基于寄存器的。 根据栈设计的优点是跨平台#xff0c;指令集小#xff0c;编译器容易实现#xff0c;缺点是性能下降#xff0c;实现同样的功…虚拟机栈的背景
由于跨平台性的设计java的指令都是根据栈来设计的。不同平台CPU架构不同所以不能设计为基于寄存器的。 根据栈设计的优点是跨平台指令集小编译器容易实现缺点是性能下降实现同样的功能需要更多的指令。
内存中的堆与栈
栈是运行时的单位而堆是存储的单位 1.栈解决程序的运行问题即程序如何执行或者说如何处理数据。堆解决的是数据存储的问题即数据怎么放、放在哪儿。
2.一般来讲对象主要都是放在堆空间的是运行时数据区比较大的一块
3.栈空间存放 基本数据类型的局部变量以及引用数据类型的对象的引用 Java虚拟机栈的特点
1.java虚拟机栈Java Virtual Machine Stack早期也叫Java栈。 每个线程在创建时都会创建一个虚拟机栈其内部保存一个个的栈帧Stack Frame对应这个一次次的java方法调用。它是线程私有的 2.生命周期和线程是一致的
3.栈是一种快速有效的分配存储方式访问速度仅次于PC寄存器程序计数器
4.作用主管java程序的运行它保存方法的局部变量、8种基本数据类型、对象的引用地址、部分结果并参与方法的调用和返回。
局部变量相较于成员变量成员变量或称属性
基本数据变量8种基本数据类型
引用类型变量类数组接口
5.JVM直接对java栈的操作只有两个
1每个方法执行伴随着进栈入栈压栈
2执行结束后的出栈工作 6.对于栈来说不存在垃圾回收问题但是肯定存在OOM异常 下面接着说Java虚拟机栈的异常
栈中可能出现的异常
java虚拟机规范允许Java栈的大小是动态的或者是固定不变的
如果采用固定大小的Java虚拟机栈那每一个线程的java虚拟机栈容量可以在线程创建的时候独立选定。如果线程请求分配的栈容量超过java虚拟机栈允许的最大容量java虚拟机将会抛出一个 StackOverFlowError异常
/*** 演示栈中的异常*/
public class StackErrorTest {public static void main(String[] args) {main(args);}
}
如果java虚拟机栈可以动态拓展并且在尝试拓展的时候无法申请到足够的内存或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈那java虚拟机将会抛出一个 OutOfMemoryError异常 设置栈的内存大小
我们可以使用参数-Xss选项来设置线程的最大栈空间栈的大小直接决定了函数调用的最大可达深度。 IDEA设置方法Run-EditConfigurations-VM options 填入指定栈的大小-Xss256k
/*** 演示栈中的异常** 默认情况下count 10818* 设置栈的大小 -Xss256k count 1872*/
public class StackErrorTest {private static int count 1;public static void main(String[] args) {System.out.println(count);count;main(args);}
}
Java虚拟机栈的存储结构和运行原理
1.每个线程都有自己的栈栈中的数据都是以栈帧(Stack Frame)的格式存在
2.在这个线程上正在执行的每个方法都对应各自的一个栈帧
3.栈帧是一个内存区块是一个数据集维系着方法执行过程中的各种数据信息
4.JVM直接对java栈的操作只有两个就是对栈帧的压栈和出栈遵循先进后出/后进先出的和原则。
5.在一条活动线程中一个时间点上只会有一个活动的栈帧。即只有当前正在执行的方法的栈帧栈顶栈帧是有效的这个栈帧被称为当前栈帧(Current Frame),与当前栈帧对应的方法就是当前方法Current Frame
6.执行引擎运行的所有字节码指令只针对当前栈帧进行操作
7.如果在该方法中调用了其他方法对应的新的栈帧会被创建出来放在栈的顶端成为新的当前栈帧。
8.不同线程中所包含的栈帧是不允许相互引用的即不可能在另一个栈帧中引用另外一个线程的栈帧
9.如果当前方法调用了其他方法方法返回之际当前栈帧会传回此方法的执行结果给前一个栈帧接着虚拟机会丢弃当前栈帧使得前一个栈帧重新成为当前栈帧
10.Java方法有两种返回函数的方式一种是正常的函数返回使用return指令另外一种是抛出异常。不管使用哪种方式都会导致栈帧被弹出。 代码示例
/*** 栈帧*/
public class StackFrameTest {public static void main(String[] args) {StackFrameTest test new StackFrameTest();test.method1();//输出 method1和method2都作为当前栈帧出现了两次method3一次
// method1()开始执行。。。
// method2()开始执行。。。
// method3()开始执行。。。
// method3()执行结束。。。
// method2()执行结束。。。
// method1()执行结束。。。}public void method1(){System.out.println(method1()开始执行。。。);method2();System.out.println(method1()执行结束。。。);}public int method2(){System.out.println(method2()开始执行。。。);int i 10;int m (int) method3();System.out.println(method2()执行结束。。。);return im;}public double method3(){System.out.println(method3()开始执行。。。);double j 20.0;System.out.println(method3()执行结束。。。);return j;}}
虚拟机栈的相关面试题
1.举例栈溢出的情况StackOverflowError
递归调用等通过-Xss设置栈的大小
2.调整栈的大小就能保证不出现溢出么
不能 如递归无限次数肯定会溢出调整栈大小只能保证溢出的时间晚一些极限情况会导致OOM内存溢出Out Of Memery Error注意是Error
3.分配的栈内存越大越好么
不是 会挤占其他线程的空间
4.垃圾回收是否会涉及到虚拟机栈
不会关于Error我们再多说一点上面的讨论不涉及Exception首先Exception和Error都是继承于Throwable 类在 Java 中只有 Throwable 类型的实例才可以被抛出throw或者捕获catch它是异常处理机制的基本组成类型。 Exception和Error体现了JAVA这门语言对于异常处理的两种方式。 Exception是java程序运行中可预料的异常情况咱们可以获取到这种异常并且对这种异常进行业务外的处理。 Error是java程序运行中不可预料的异常情况这种异常发生以后会直接导致JVM不可处理或者不可恢复的情况。所以这种异常不可能抓取到比如OutOfMemoryError、NoClassDefFoundError等。 其中的Exception又分为检查性异常和非检查性异常。两个根本的区别在于检查性异常 必须在编写代码时使用try catch捕获比如IOException异常。非检查性异常 在代码编写使可以忽略捕获操作比如ArrayIndexOutOfBoundsException这种异常是在代码编写或者使用过程中通过规范可以避免发生的。
5.方法中定义的局部变量是否线程安全
要具体情况具体分析
/*** 面试题* 方法中定义的局部变量是否线程安全具体情况具体分析** 何为线程安全* 如果只有一个线程可以操作此数据则必定是线程安全的。* 如果有多个线程操作此数据则此数据是共享数据。如果不考虑同步机制的话会存在线程安全问题** 我们知道StringBuffer是线程安全的源码中实现synchronizedStringBuilder源码未实现synchronized,在多线程情况下是不安全的* 二者均继承自AbstractStringBuilder**/
public class StringBuilderTest {//s1的声明方式是线程安全的s1在方法method1内部消亡了public static void method1(){StringBuilder s1 new StringBuilder();s1.append(a);s1.append(b);}//stringBuilder的操作过程是不安全的因为method2可以被多个线程调用public static void method2(StringBuilder stringBuilder){stringBuilder.append(a);stringBuilder.append(b);}//s1的操作是线程不安全的 有返回值可能被其他线程共享public static StringBuilder method3(){StringBuilder s1 new StringBuilder();s1.append(a);s1.append(b);return s1;}//s1的操作是线程安全的 StringBuilder的toString方法是创建了一个新的Strings1在内部消亡了public static String method4(){StringBuilder s1 new StringBuilder();s1.append(a);s1.append(b);return s1.toString();}public static void main(String[] args) {StringBuilder s new StringBuilder();new Thread(()-{s.append(a);s.append(b);}).start();method2(s);}}