java代码是在线程中被执行的。每个线程都有它自己的执行栈,这个栈由很多帧组成。每个帧代表了一个方法调用:每当一个方法被调用时,就会创建一个新的帧,然后将这个帧放到当前线程的执行栈的栈顶。当这个方法正常返回时,或者发生了异常,这个帧就会从执行栈顶弹出,然后虚拟机会接着执行下一个位于执行栈栈顶的帧。
每个帧都包含两部分:一个局部变量区和一个操作数栈区。局部变量区包含了方法中定义的局部变量,可以通过索引值来随即访问。操作数栈区,如它的名字暗示,它是一个包含操作数的栈,这些数据被字节码指令所使用。这意味着这个栈中的数据只能以后进先出的顺序访问。
局部变量区和操作数栈的大小是由方法中的代码决定的。它们的大小是在编译时计算的,然后随着字节码指令一起存储在编译后的类中。
当帧被创建的时候,操作数栈初始化为空,局部变量包含当前对象的引用this(非静态方法)以及方法的参数。
局部变量区和操作数栈区的每一个插槽(图3.1中的方框)都能存储java中的任何值,除了long型和double型的值。因为long和double值需要2个插槽。
字节码指令可以划分为两类:1将局部变量的值传递到操作数栈的一小部分指令集,另外一部分指令2在操作数栈上进行操作:它们取得栈顶上的一些数据,进行计算,获得结果,然后将结果放回栈顶。
常见的指令1:
ILOAD,LLOAD,FLOAD,DLOAD和ALOAD指令读取一个局部变量的值,然后将它放置到操作数栈,这些指令的参数就是需要读取的局部变量的索引值i。
ISTORE,LSTORE,FSTORE,DSTORE和ASTORE指令是用来从操作数栈取得相应的数据然后保存会局部变量,它们的参数也是索引值i。
示例:
package pkg; public class Bean { private int f; public int getF() { return this.f; } public void setF(int f) { this.f = f; } }
其中getter方法的字节码为:
ALOAD 0
GETFIELD pkg/Bean f I
IRETURN
第一条指令读取索引位置为0的局部变量this,这个局部变量是在这个方法调用时创建的帧的过程中被初始化的,然后将这个局部变量放置到操作数栈栈顶。第二条指令从栈顶弹出这个值,this,然后将字段f的值放置到栈顶,this.f。最后一条指令从栈顶弹出得到的字段f的值,将它返回给调用者。这个方法执行过程中帧的状态如图
Setter方法的字节码如下:
ALOAD 0
ILOAD 1
PUTFIELD pkg/Bean f I
RETURN
第一条指令将this放置到操作数栈栈顶。第二条指令将索引为1的局部变量值放置到栈顶,这个索引的值为方法的参数,在方法调用创建帧的过程中初始化的。第三个指令从栈顶弹出这两个值,并将int值存贮到this对象的字段f中,this.f。最后一条指令,在源代码中是隐
式定义的,但是在编译后的代码中是必须的,它负责销毁执行帧并将调用返回给调用者。这个方法的执行帧的状态如图:
再看一个实际工作代码中某个类的一个方法
java代码如下:
/** * 并行计算各Handler * @param services * @param describerMap * @param items * @param snapshots * @param areaId * @param option * @param context * @param fees * @param demoteLines */ private void asynHandle(List<Long> services, Map<Long, PostageDescriberDO> describerMap, List<ItemDesc> items, Map<Long, TemplateSnapshotTO> snapshots, long areaId, DeliveryQueryOption option, MojoContext context, List<FeeDesc> fees, List<DemoteLine> demoteLines) { Mailbox<ExitMsg> exitmb = new Mailbox<ExitMsg>(); FlowTask resTask = new FlowTask(); for (Long service : services) { if(DeliveryConstant.ignoreServices.contains(service)) { continue; } PostageDescriberDO describer = describerMap.get(service); if (describer != null && describer.getType().intValue() != DeliveryConstant.DELIVERY_TYPE_ADV) { MojoEvent event = new MojoEvent(items, snapshots, service, areaId, option, context); FlowTask preTask = new HandlerCalTask(event, fees, demoteLines); Long dependencyType = DeliveryConstant.serviceMapping.get(service); Mailbox<ExitMsg> exitFlag = new Mailbox<ExitMsg>(); if(dependencyType != null && services.contains(dependencyType)) { MojoEvent mojoEvent = new MojoEvent(items, snapshots, dependencyType, areaId, option, context); FlowTask task = new HandlerCalTask(mojoEvent, fees, demoteLines); Mailbox<ExitMsg> exitMsg = new Mailbox<ExitMsg>(); preTask.informOnExit(exitMsg); //开启执行前置任务 preTask.start(); //添加子任务 resTask.addSubFlowTask(task); task.informOnExit(exitFlag); //preTask设置为task的前置任务,通过exitMsg识别 task.addPreTaskExtMsg(exitMsg); } else { //添加子任务 resTask.addSubFlowTask(preTask); preTask.informOnExit(exitFlag); } //添加子任务完成标记 resTask.addSubTaskExtMsg(exitFlag); } } resTask.start(); resTask.informOnExit(exitmb); exitmb.getb(2000);//超时时间 }
该方法的字节码为:
private asynHandle(Ljava/util/List;Ljava/util/Map;Ljava/util/List;Ljava/util/Map;JLcom/taobao/delivery/common/transfer/query/DeliveryQueryOption;Lcom/taobao/delivery/common/mojo/MojoContext;Ljava/util/List;Ljava/util/List;)V NEW kilim/Mailbox DUP INVOKESPECIAL kilim/Mailbox.<init> ()V ASTORE 11 NEW com/taobao/delivery/common/kilim/FlowTask DUP INVOKESPECIAL com/taobao/delivery/common/kilim/FlowTask.<init> ()V ASTORE 12 ALOAD 1 INVOKEINTERFACE java/util/List.iterator ()Ljava/util/Iterator; ASTORE 14 GOTO L0 L1 FRAME FULL [com/taobao/delivery/common/mojo/DeliveryMojo java/util/List java/util/Map java/util/List java/util/Map J com/taobao/delivery/common/transfer/query/DeliveryQueryOption com/taobao/delivery/common/mojo/MojoContext java/util/List java/util/List kilim/Mailbox com/taobao/delivery/common/kilim/FlowTask T java/util/Iterator] [] ALOAD 14 INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object; CHECKCAST java/lang/Long ASTORE 13 GETSTATIC com/taobao/delivery/common/constant/DeliveryConstant.ignoreServices : Ljava/util/List; ALOAD 13 INVOKEINTERFACE java/util/List.contains (Ljava/lang/Object;)Z IFEQ L2 GOTO L0 L2 FRAME FULL [com/taobao/delivery/common/mojo/DeliveryMojo java/util/List java/util/Map java/util/List java/util/Map J com/taobao/delivery/common/transfer/query/DeliveryQueryOption com/taobao/delivery/common/mojo/MojoContext java/util/List java/util/List kilim/Mailbox com/taobao/delivery/common/kilim/FlowTask java/lang/Long java/util/Iterator] [] ALOAD 2 ALOAD 13 INVOKEINTERFACE java/util/Map.get (Ljava/lang/Object;)Ljava/lang/Object; CHECKCAST com/taobao/delivery/common/dataobject/PostageDescriberDO ASTORE 15 ALOAD 15 IFNULL L0 ALOAD 15 INVOKEVIRTUAL com/taobao/delivery/common/dataobject/PostageDescriberDO.getType ()Ljava/lang/Integer; INVOKEVIRTUAL java/lang/Integer.intValue ()I ICONST_1 IF_ICMPEQ L0 NEW com/taobao/delivery/common/mojo/MojoEvent DUP ALOAD 3 ALOAD 4 ALOAD 13 LLOAD 5 INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long; ALOAD 7 ALOAD 8 INVOKESPECIAL com/taobao/delivery/common/mojo/MojoEvent.<init> (Ljava/util/List;Ljava/util/Map;Ljava/lang/Long;Ljava/lang/Long;Lcom/taobao/delivery/common/transfer/query/DeliveryQueryOption;Lcom/taobao/delivery/common/mojo/MojoContext;)V ASTORE 16 NEW com/taobao/delivery/common/kilim/HandlerCalTask DUP ALOAD 16 ALOAD 9 ALOAD 10 INVOKESPECIAL com/taobao/delivery/common/kilim/HandlerCalTask.<init> (Lcom/taobao/delivery/common/mojo/MojoEvent;Ljava/util/List;Ljava/util/List;)V ASTORE 17 GETSTATIC com/taobao/delivery/common/constant/DeliveryConstant.serviceMapping : Ljava/util/Map; ALOAD 13 INVOKEINTERFACE java/util/Map.get (Ljava/lang/Object;)Ljava/lang/Object; CHECKCAST java/lang/Long ASTORE 18 NEW kilim/Mailbox DUP INVOKESPECIAL kilim/Mailbox.<init> ()V ASTORE 19 ALOAD 18 IFNULL L3 ALOAD 1 ALOAD 18 INVOKEINTERFACE java/util/List.contains (Ljava/lang/Object;)Z IFEQ L3 NEW com/taobao/delivery/common/mojo/MojoEvent DUP ALOAD 3 ALOAD 4 ALOAD 18 LLOAD 5 INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long; ALOAD 7 ALOAD 8 INVOKESPECIAL com/taobao/delivery/common/mojo/MojoEvent.<init> (Ljava/util/List;Ljava/util/Map;Ljava/lang/Long;Ljava/lang/Long;Lcom/taobao/delivery/common/transfer/query/DeliveryQueryOption;Lcom/taobao/delivery/common/mojo/MojoContext;)V ASTORE 20 NEW com/taobao/delivery/common/kilim/HandlerCalTask DUP ALOAD 20 ALOAD 9 ALOAD 10 INVOKESPECIAL com/taobao/delivery/common/kilim/HandlerCalTask.<init> (Lcom/taobao/delivery/common/mojo/MojoEvent;Ljava/util/List;Ljava/util/List;)V ASTORE 21 NEW kilim/Mailbox DUP INVOKESPECIAL kilim/Mailbox.<init> ()V ASTORE 22 ALOAD 17 ALOAD 22 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.informOnExit (Lkilim/Mailbox;)V ALOAD 17 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.start ()Lkilim/Task; POP ALOAD 12 ALOAD 21 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.addSubFlowTask (Lcom/taobao/delivery/common/kilim/FlowTask;)V ALOAD 21 ALOAD 19 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.informOnExit (Lkilim/Mailbox;)V ALOAD 21 ALOAD 22 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.addPreTaskExtMsg (Lkilim/Mailbox;)V GOTO L4 L3 FRAME FULL [com/taobao/delivery/common/mojo/DeliveryMojo java/util/List java/util/Map java/util/List java/util/Map J com/taobao/delivery/common/transfer/query/DeliveryQueryOption com/taobao/delivery/common/mojo/MojoContext java/util/List java/util/List kilim/Mailbox com/taobao/delivery/common/kilim/FlowTask java/lang/Long java/util/Iterator com/taobao/delivery/common/dataobject/PostageDescriberDO com/taobao/delivery/common/mojo/MojoEvent com/taobao/delivery/common/kilim/FlowTask java/lang/Long kilim/Mailbox] [] ALOAD 12 ALOAD 17 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.addSubFlowTask (Lcom/taobao/delivery/common/kilim/FlowTask;)V ALOAD 17 ALOAD 19 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.informOnExit (Lkilim/Mailbox;)V L4 FRAME SAME ALOAD 12 ALOAD 19 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.addSubTaskExtMsg (Lkilim/Mailbox;)V L0 FRAME FULL [com/taobao/delivery/common/mojo/DeliveryMojo java/util/List java/util/Map java/util/List java/util/Map J com/taobao/delivery/common/transfer/query/DeliveryQueryOption com/taobao/delivery/common/mojo/MojoContext java/util/List java/util/List kilim/Mailbox com/taobao/delivery/common/kilim/FlowTask T java/util/Iterator] [] ALOAD 14 INVOKEINTERFACE java/util/Iterator.hasNext ()Z IFNE L1 ALOAD 12 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.start ()Lkilim/Task; POP ALOAD 12 ALOAD 11 INVOKEVIRTUAL com/taobao/delivery/common/kilim/FlowTask.informOnExit (Lkilim/Mailbox;)V ALOAD 11 LDC 2000 INVOKEVIRTUAL kilim/Mailbox.getb (J)Ljava/lang/Object; POP RETURN MAXSTACK = 8 MAXLOCALS = 23
MAXSTACK 是方法执行时分配的局部变量区的插槽个数。
MAXLOCALS 是方法执行时操作数栈的插槽个数。
ALOAD 12的意思就是加载一个非基本类型,在局部变量区插槽序号是12的一个对象类型到操作数栈顶