一种用于硬实时Java处理器的类装载器的设计

一种用于硬实时Java处理器的类装载器的设计
沈袁柴志雷须文波
(江南大学信息工程学院江苏无锡214122)
0 引 言
近年来嵌入式系统发展极其迅速,正逐步渗透于人类生活
的各个方面,这对嵌入式系统的性能及开发效率也提出了更高
的要求。目前嵌入式软件开发普遍还使用C/C++甚至汇编语
言进行,难以适应嵌入式系统的迅猛发展,因此需要新的开发方
法和开发手段来解决。Java语言的面向对象、跨平台、语言级并
发支持、安全等特性引起了嵌入式领域研究人员的高度重视。
针对传统Java技术在实时方面的不足,Sun公司制定了实时Ja—
va规范(RTSJ)0 。由此针对实时Java的研究正成为热点,有
一些公司提出了Java的实时解决方案,比方说esmertec、New—
Monics,但这些供应商的产品都不支持RTSJ。考虑到Java处理
器在执行效率、功耗上的优势,支持RTSJ的实时Java处理器是
一个值得深入的研究方向。
为此,我们设计了一个适合于硬实时Java处理器上运行的
类装载器,它采用静态装载连接方式,除了能把class文件转化
成适合Java处理器直接执行的内存映像文件外,还对装载过程
和字节码指令进行了实时性优化。它能够提高指令最坏情况下
执行时间(WCET)的可预测性,并为面向性能更好的Java处理
器作好了准备。
1 类装载器的设计
1.1 装载过程的实时性优化
Java源代码经过编译器编译后为每个Java类型(包括类和
接口)生成一个Java class文件,类装载器除了要定位和导入二
进制class文件,还必须负责验证被导入类的正确性,为类变量
分配并初始化内存,以及帮助解析符号引用。
传统的Java虚拟机采用了动态装载的方式,指令集不优
化,在运行过程中会反复涉及上述这些处理工作,大量地验证
准备和解析工作都极大地影响了系统的实时性。本文设计的类
装载器采用静态装载连接方式,API位于Pc,指令集优化,在程
序执行前完成了对所有类的装载,提高了系统的实时性。
为了支持RTSJ中的机制,装载器还进行了一些预处理来避
免对系统运行时实时性的影响,如:
· 异步控制转移 该机制对于实时应用来说极其重要。
它使得一个线程可以抛出一个异常给另外一个线程,完成线程
间通信,或终止另一个线程的执行。采用文献[2]的处理,可以
使目标线程在捕获抛给自己的异常时,其匹配过程的WCET可
预测。
· 内存管理为了支持那些不能容忍被垃圾收集打断的
任务,RTSJ定义了不朽(immorta1)和作用域内存,以补充标准的
Java堆。分配在不朽内存中的对象可以被所有的线程访问并且
从来不会被收集。而作用域内存可以由程序员来创建和销毁。
每个作用域内存按最大空间分配,并且可以用于对象分配。为
了确保对象之间引用的完整性,RTSJ定义了管理一个内存区域
(堆、不朽内存、作用域内存)中的对象如何引用其他内存区域
对象的规则。其中很多规则定义了作用域内存中的对象何时终
结,以及何时可以重用内存区域。采用文献[3]提出的内存管
理模式使得WCET很容易预测。
1.2 字节码指令优化
为了进~步提高实时性和WCET的可预测性,装载器还需
要对字节码指令进行优化。文献[4]对此已经做了~ 些工作,
而我们进一步完善了部分指令,以适合新的需要:
1)getfield和putfield指令
标准字节码通过解析常量池获得字段的宽度,以及从对象
映像的起始点开始的字段偏移量来访问实例字段。利用该类装
载器的预处理,可以通过读取类文件把实例字段偏移量和字段
宽度直接保存在修改过的字节码中。
处理前:getfield,indexbytel,indexbyte2
处理后:getfield,width,oftbytel,ofbyte2
同样,putfield,indexbytel,indexbyte2可以修改为putfield,
width,offbytel,offbyte2。其中indexbytel,indexbyte2为常量池入
口索引;width为字段宽度;ofbytel,offbyte2为字段偏移量。
2)getstatic和putstatic指令
对于静态字段来说,标准字节码需要解析运行时常量池获
得静态字段的地址和宽度来访问该字段。通过该类装载器的预
处理,可以把字段地址和宽度直接保存在修改过的字节码中。
处理前:getstatic,indexbytel,indexbyte2
处理后:getstatic,width,addrl,addr2
同样,putstatic,indexbytel,indexbyte2可以修改为putstatic,
width,addrl,addr2。其中addrl,addr2为静态字段绝对地址。
3)anewarray指令
对于创建引用数组对象指令来说,标准字节码需要解析常
量池来获得引用类型。如果操作成功,Java虚拟机创建一个长
度为count,数据类型为常量池入口所指明的引用类型的数组。
通过类装载器的处理,我们直接算出数组引用类型所占的字节
数reflength,把count =reflength作为数组大小,indexbytel,indexbyte2
不再使用。
处理前:put count
anewarray ,indexbytel,indexbyte2
处理后:put count//把count压入栈
anewarry//分配count =reflength字节的空间
上述被优化过的指令可以根据不同需要而灵活地被使用。
比如在实验环境简单的情况下,我们可以把字段宽度width和
数组引用类型所占的字节数reflength设为默认长度,这样width
可以不用,在计算引用数组大小时也可以减少对内存的读取操
作。但在32位数以上的处理器中,一般不把它们的值设为默
认。
4)new指令
当创建一个类的新实例时,需要为保存对象的实例变量分
配空间,所有在对象的类和它的超类中声明的变量都要分配内
存。这个过程很复杂,并且WCET无法预测。
现在我们通过该装载器的处理,提前计算出实例空间大小
ObjSize。new创建的新对象有可能是普通对象,作用域内存对
象或者不朽内存对象。普通对象需要知道对象大小,返回创建
好的对象引用。作用域内存对象或者不朽内存对象不需要知道
大小,只返回对象引用。所以,我们设定:ObjSize=一1表示创
建的是作用域内存对象。ObjSize: 一2表示创建的是不朽内存
对象。ObjSize为其他值时表示创建的是普通对象。为了避免
运行时解析常量池,还需要把对象所属类的信息放在字节码本
身。
处理前:new,indexbytel,indexbyte2
处理后:new,ObjSizel,ObjSize2,ClassAddr1.ClassAddr2
其中indexbytel,indexbyte2为常量池入El索引;ClassAddrl,Clas.
sAddr2为对象所属类在处理器内存中的地址。
由此可见,Java处理器在执行经过类装载器处理的上述指
令时,总能够直接获得相关信息,运行时常量池不再使用,保证
了实时性和WCET的可预测性。
1.3 类装载器处理流程
类装载器将按如下顺序对class文件进行处理,最后生成适
合Java处理器直接执行的内存映像文件:
① 类装载器装载main()方法所在的类,分析有无超类,若
有且还没有被装载,则装载其超类,直至所有超类被装载完毕。
然后从上面循环装载进来的最顶端的那个类开始预处理每个被
装载的类,直到起点类。预处理的工作主要是累计各种空间的
总大小,如类中方法引用及方法本身所占空间,运行时常量池大
小和每个方法的偏移量等。
② 以main方法为起点分析字节码,如果字节码引用到了
别的类,就把引用到的类装进来;如果是方法调用,则递归地装
载被调用方法所在的类。通过以上步骤,所有涉及到的类都已
经被装载进来了。
③ 遍历已经装载的每个类,从起始地址处为<clinit>方法
分配空间。
④ 分配方法表,随后给所有类中定义的方法(包括本地和
非本地的,<clinit>单独处理)分配空间,并记录各项地址。扫
描方法表,把各个方法引用填充到相应表项中。为常量池、字段
和字符串分配空间,把字符串写入到内存映像中。整个分配过
程中需要判断是否内存溢出。
⑤ 遍历已经装载的每个类,处理其<clinit>方法,分析字
节码并把修改后的字节码写入内存映像文件,同时填充相应常
量池入口。
⑥ 从main入口开始检查内存的对象引用规则。由于<
clinit>方法中引用的都是静态变量,所以不需要检查。
⑦ 以main方法为起点,分析字节码,处理涉及到的方法,
并将修改后的字节码写入内存映像文件,同时填充相应常量池
入口。前面讨论的字节码指令优化也在这个步骤里处理。
2 实验结果
本节以如下示例程序来讨论标准的Class文件经过类装载
器处理后所得的结果。

  1. impo~javax.realtime. ;
  2. public class HelloThread extends ReahimeThread
  3. {
  4. static final int Const=255;
  5. static int x=0:
  6. static int Y 0;
  7. String S=null;
  8. String S2=null:
  9. public HelloThread(MemoryArea nlem )
  10. {
  11. super(null,null,null,mem,null,nul1);
  12. this.setName(men.getClass().getName());
  13. X=123:
  14. Y=456;
  15. }
  16. public void run()
  17. {
  18. s= this.getName()+ ”Hello World”:
  19. System.out.println(S);
  20. s2=this.getName()+”Consumed”+this.getMemoryArea().
  21. memoryConsumed()+ ”bytes”;
  22. System.out.println(s2);
  23. }
  24. public static void main(String[]args)
  25. {
  26. HelloThread tl = new HelloThread
  27. (ImmortalMem0ry.instance());
  28. LTMemory hmem =new LTMemo~(8192,32768);
  29. HelloThread t2 =new HelloThread(hmcm );
  30. t1.start();
  31. t2.start();
  32. System.out.println(”Finished Main Thread”);
  33. }
  34. }

复制代码

表1说明示例程序的Class文件经过类装载器处理后各区
域在映像文件中的起始地址。
2.JPG

下载 (49.26 KB)

8 小时前

3.JPG

下载 (34.64 KB)

8 小时前

4.JPG

下载 (50.74 KB)

8 小时前

3 结束语
本文设计了一种能被用于不同位数的硬Java处理器的类
装载器,它采用了静态装载连接方式,可以把class文件转化成
适合Java处理器直接执行的内存映像文件。它对装载过程和
字节码指令进行了实时性优化,提高了最坏情况执行时间
(WCET)的可预测性。该装载器可以在PC端运行,不占用运
行时处理器的资源,有着对芯片存储空问要求低、效率高的优
点。

 

(本文出自教程天下 www.nba114.com转载请注明)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值