同步操作将从 icanci/Java-Review 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
// StackOverflowError
public class InvokeSelf {
public static void main(String[] args) {
main(args);
}
}
栈内存大小:-Xss 以字节为单位 ,单位是可以调节的
public class InvokeMethodFrame {
public static void main(String[] args) {
System.out.println("InvokeSelf.main 开始执行...");
method1();
System.out.println("InvokeSelf.main 执行结束...");
}
public static void method1() {
method2();
System.out.println("InvokeSelf.method1");
}
public static void method2() {
method3();
System.out.println("InvokeSelf.method2");
}
public static void method3() {
method4();
System.out.println("InvokeSelf.method3");
}
public static void method4() {
System.out.println("InvokeSelf.method4");
}
}
InvokeSelf.main 开始执行...
InvokeSelf.method4
InvokeSelf.method3
InvokeSelf.method2
InvokeSelf.method1
InvokeSelf.main 执行结束...
参数值的存放总是在局部变量数组的index0开始,到数组长度 -1 的索引结束
局部变量表。最基本的存储单元是Slot(变量槽)
局部变量表中存放编译器可知的各种基本数据类型(8种),引用类型(reference),returnAdderss类型的变量
在局部变量表种。32位以内的类型只占用一个Slot(包括returnAddress类型),64位的类型(long和double)占用2个Slot
JVM会为局部变量表中的每一个Solt都分配一个访问索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值
当一个实例方法被调用的时候,它的方法参数和方法体内部定义的局部变量将会 按照顺序被复制 到局部变量表中的每一个Slot上
如果需要访问局部变量表中的一个64bit的局部变量只值的时候,只需要使用前一个索引即可,(比如:访问long和double类型的变量)
如果当前帧是由构造方法或者实例方法创建的,那么 该对象引用this将会存放在index为0的Slot处,其余的参数按照参数表顺序继续排列
Slot的重复利用
栈可以使用数组和链表来实现
**如果被调用的方法带有返回值的话,其返回值将会被压入当前栈帧的操作数栈中,**并更新PC寄存器的下一条需要执行的字节码指令
操作数栈中元素的数据类型必须与字节码指令的序列严格匹配,这由编译器再编译期间进行验证,同时在类加载中的类检验阶段的数据流分析阶段要再次验证
我们说的Java虚拟机的解释引擎时基于栈的执行引擎,其中的栈指的就是操作数栈
操作数栈,主要用来保存计算过程中的中间结果,同时作为计算过程中变量的临时存储空间
操作数栈就是JVM执行引擎的一个工作区,当一个方法刚开始执行的时候,一个新栈帧也随之被创建出来,这个方法的操作数栈时空的
每一个操作数栈都会拥有一个明确的栈深度用于存储数值,其所需的最大深度在编译器就定义好了,保存在方法的Code属性中,为max_stack的值
栈中的任何一个元素都可以是任意的Java数据类型
操作数栈 并发采用访问索引的方式来进行数据访问的,而是只能通过标准的入栈(push)和出栈(pop)操作来完成一次数据访问
public class JvmStackTest {
public static void main(String[] args) {
}
public void testAddOperation() {
byte i = 15;
int j = 8;
int k = i + j;
}
}
public void testAddOperation();
descriptor: ()V
flags: ACC_PUBLIC
Code:
// 栈的最大深度为2 局部变量表大小为4 其中非静态方法还有个this在index=0的位置
stack=2, locals=4, args_size=1
0: bipush 15
2: istore_1
3: bipush 8
5: istore_2
6: iload_1
7: iload_2
8: iadd
9: istore_3
10: return
LineNumberTable:
line 16: 0
line 17: 3
line 18: 6
line 19: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this Lcn/icanci/jvm/jmm/JvmStackTest;
3 8 1 i B
6 5 2 j I
10 1 3 k I
}
SourceFile: "JvmStackTest.java"
放在字节码解释
public void testIadd() {
int i = 1;
i++;
int j = 1;
++j;
}
为什么需要常量池呢?
虚方法与非虚方法
虚拟机中提供的方法调用的指令
关于involvedynamic指令
存放着调用该方法的PC寄存器的值
一个方法的结束,有两种方式
无论通过那种方式退出,在方法退出后都返回到该方法被调用的位置,方法正常退出的时候,调用者的PC寄存器的值作为返回地址,即调用该方法的指令的下一条指令的地址。而通过异常退出的,返回的地址是要通过异常表来确定,栈帧中一般不会保持这部分的信息。
本质上,方法的退出即使当前栈帧出栈的过程。此时,需要恢复上层方法的局部变量表、操作数栈、讲返回值压入调用者栈帧的操作数栈、设置PC寄存器值等,让调用者方法继续执行下去
正常完成出口和异常完成出口的区别在于:通过异常出口完成退出的不会给它的上层调用者产生任何的返回值
当一个方法开始执行之后,只有两种方式可以退出这个方法
一个方法在正常调用完成之后究竟需要使用哪一个返回指令还需要根据方法返回值的实际数据类型而定
在字节码指令中,返回指令包含 ireturn (返回值是boolean、byte、char、short和int类型时使用),lreturn、freturn、dreturn、areturn,另外还有一个return指令共声明void方法、实例化初始方法、类和接口的初始方法使用
在方法执行的过程中遇到了异常(Exception),并且这个异常没有在方法内进行处理,也就是只要在本地方法异常表没有搜索到匹配的异常处理器,就会导致方法退出,检查 异常完成出口
方法执行过程中抛出异常时的异常处理,存储在一个异常处理表。方便在发生异常的时候找到处理异常的代码
public class JvmExceptionTest {
public static void main(String[] args) {
try {
test1();
} catch (NoSuchMethodException e) {
} catch (ClassNotFoundException e) {
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test1() throws NoSuchMethodException, ClassNotFoundException, Exception {
}
}
Exception table:
from to target type
0 3 6 Class java/lang/NoSuchMethodException
0 3 10 Class java/lang/ClassNotFoundException
0 3 14 Class java/lang/Exception
/**
* 内部产生,内部消亡的,就是安全的,否则就是不安全的
* 这里没有共享变量的问题,除非是返回非安全的,或者有传入参数的
*/
public class StringBuilderTest {
/**
* 此时是线程安全的
*/
public static void method1() {
// StringBuilder 线程不安全的
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(sb.toString());
}
/**
* 不是线程安全的
*
* @param sb
*/
public static void method2(StringBuilder sb) {
sb.append("a");
sb.append("b");
}
/**
* 线程不安全的 可能有多个线程枪 sb
*
* @return
*/
public static StringBuilder method3() {
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
return sb;
}
/**
* 是线程安全的
*
* @return
*/
public static String method4() {
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
return sb.toString();
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
method1();
}).start();
}
System.out.println();
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。