2007年08月10日

Mark Lam has been a virtual machine engineer in the JavaME CDC team at Sun Microsystems for over 6 years. Before joining Sun, he was a real-time embedded systems developer for 6+ years, working on application frameworks, graphics systems, networking protocols, game development, and fault tolerant systems amongst other things, on devices ranging from 64KB 8bit uControllers to 32-bit RISC machines.

原文URLhttp://weblogs.java.net/blog/mlam/archive/2006/11/multitasking_th_1.html

 

         今天,我在java.net论坛看到了这个讨论。它让我感到惊奇,假如所有人都意味着同一个事情,如果当他们在谈论java平台的多任务时。因此,我决定今天暂停讨论CVM,开始多任务(这也与phoneME和CVM相关)

不承诺:在开始前,我必须阐明我的观点只代表我个人,不代表Sun,我的雇主,我在Sun的同事。

什么是多任务?

       严格的说,多任务意味着同一时间能做多个事情。对JAVA平台,这意味着能够有同时执行的代码。JAVA平台已经支持多任务。因此,这个问题是什么?人们想同时更好的运行多个程序。这到底和从不同的线程调用程序的main()函数有什么不同?不同是,程序想要自己的世界和所有的资源。简单的运行它们在不同的线程可能只有边缘效果,当一个程序能同其他操作交互的时候。因此,一个多任务JAVA平台需要能够分别隔离那些程序。那么,我在那里听到的这些特性点和行为?为什么这是现在操作系统的普遍应用。

       因此,当人们想要多任务的时候,我想他们是想要求一个JAVA进程,JAVA平台代替这些系统相关的角色。让我们看看多任务特点在系统中,看看这些在JAVA平台下证明了什么。我们应该关心人们想要的这些特点。让我们先从系统开始。。。

系统透视

       如果我们为JAVA平台处理,他们应该有下面的特点:

特点                            JAVA平台包含

同时(Concurrency)        多程序能同一时间运行在同一设备上。系统能够

                  保证程序间资源的合理分配

隔离(Isolation)          每个程序必须有自己的VM环境。一个程序不能同

                  其他同时运行的程序冲突。在错误的程序环境中,              

                  错误和不良行为能被检测

可靠的终止(Reliable Termination)  当程序出错,程序管理器必须能够中止程序并可靠

                  的回收资源

效率(Efficiency)          减少资源使用的冗余,在程序间最大限度的共享

                  资源。在JAVA VM对每个程序初始化的时候减

                  少冗余

JSR 121 Application Isolation API 定义了API来管理这些特点。同隔离成为系统处理。无论如何,有API并不是就有了执行。

人们想要什么

       这儿有一些解释关于人们为什么想要多任务。这些例子不一定能详细,但我想它们很现实,能够马上解决这个问题。

问题1:你工作在一个运行不支持进程简单嵌入式系统的设备,你不能提供系统升级因为所有的本地代码你都已经投资。升级意味着移植所有的原始代码到新的系统,这非常昂贵。你已经为所有的系统代码的许可付了钱。但是你想同时在设备上运行多个程序,程序由你不能控制的第三方提供。用户甚至需要运行一些从网络上下载的程序。不幸的,如果你的设备crash或者开始运行缓慢,你的用户将责备你而不是程序,尽管他10岁的儿子是从不安全的站点下载的程序。

       那么,你考虑。。。JAVA平台是一个虚拟运行环境,为什么你不仅仅让它保持,当程序要向其他程序或系统做坏事的时候?问题解决!

问题2你写了一个浏览程序,需要运行JAVA程序作为插件。当你不需要它时,你可以让它到一边去而不消耗资源。你想JAVA VM提供这些。但现在,你的系统本地API不能给你一个方便的方法让你做这个。自从JAVA VM被作为一个库被装载来匹配你的浏览程序。如果你使用系统特性来赶走VM,你将结束你的浏览程序,或者让它僵死而挂起。这会让你看到不好的东西。

       那么,你考虑。。。JAVA VM是一个装载程序的东西,对吗?为什么你不把程序结束并让它自己清理干净?问题解决。

问题3你需要同时在你的设备上运行多个java程序,但系统不让java程序共享资源。。。或者资源不够。

       你考虑。。。不少所有的java程序都需要同一个class libraries来运行?为什么JAVA VM不让他们共享内存中的同一副本?问题解决!

不够快

考虑这些。。。

       对问题1,为什么执行器不考虑执行隔离在它自己的程序里,或者改善嵌入系统来做这些?毕竟JAVA VM也是软件的一块,它也从它的程序里被启动。如果它能够改善它的系统隔离能力,那每一个启动的JAVA VM都能有它自己的进程,它的问题就会被解决。

       对问题2,为什么执行器不考虑执行,在浏览程序里,一个资源跟踪系统捕获所有被JAVA VM使用的资源和正在运行的程序?如果浏览器能跟踪所有它的资源,那么它能杀死VM和程序线程,收回所有它自己的资源。

       对问题3,为什么执行器不试着改善系统(或者询问系统提供商)来多更好的工作在共享普通资源?

       对所有3个问题的答案:这是很困难的。。。非常困难。转移这些问题到JAVA平台不会让它变容易。现在好了,这儿有几个信息,JAVA VM有可能很高机会完成这个目标。但本质上,这个问题没有变容易。

       我只想让你考虑这个问题的复杂性。当你自己解决了一个问题,你的感谢为它改变。多任务不是一个价值不高的特性,Sun或其他JAVA平台提供商能够发出其他弹点在他们的成品线路图。执行多任务是一个主要承诺

       Sun已经发出了2个多任务虚拟机解决方案对CLDCCDC,让我们看看它们怎么工作?

引擎盖下是什么?

       上面3个举例的每一个是多任务的3个不同的需要:隔离(isolation)、可靠的终止(reliable termination)、效率(efficiency)。在现实生活中,这些特性的几个或全部都需要集中在一起。

       我不会同时谈论这些特性,因为它们不是解决方案的难点。JAVA平台已经支持同时执行线程。它不是太多延伸对建立程序并发。除非你需要一些特殊的进程安排道具,我会离开这个讨论。

隔离(isolation

       CLDC不支持一个本地接口对本地方法。在实践中,大多数的CLDC程序是MIDlets,它是100%的纯java代码。因此,CLDC MVM只需要处理java statejava bugs的隔离

       java state方面,我的意思是类静态域(class static fields),一个实例被系统库使用。系统库被所有的程序使用。不需要隔离,每个程序都能够在系统库里看到其他程序的操作。

       一个java bug的例子是僵死状态。一个程序有2个线程同步操作2个不同的对象在对立面。结果,每个线程将会锁住来等待另外的线程来释放其它的锁定,每个线程将永远锁定来等待其它线程。无隔离,其它程序线程可能会同步同一个对象并永久的锁住。因此,一个行为不好的程序问题会导致其它行为良好的程序。

CLDC隔离

       CLDC MVM的解决方法是复制(replicating)所有静态域在系统库中。每个隔离得到它自己的一份拷贝。结果,类/静态初始化需要对每个隔离运行一次,来保证静态拷贝的初始化是隔离的。在这个机制下,每个隔离会创建它们自己单一对象的拷贝在系统中。

    CLDC隔离同样涉及一些小把戏来确保不同的程序得到不同的锁定实例当同步在ROMized 类和字符串实例这些不能在 JAVA VM中复制的。实际字符串(interned strings)被同样的对待。

    拥有java 状态自动隔离结果在java bugs的隔离中。如果一个程序僵死,其他程序不会受到影响因为僵死程序的java state对它们不可见。

    这儿有另外一种java bug:恶意程序有目的的做一些拒绝服务(DoS)攻击对其他程序。一个例子是消耗完所有可用内存让其他程序不能运行。CLDC MVM依靠每个隔离实行资源配给来解决这个问题。如果一个隔离试图获得额外的资源,它会得到一个内存不够(OutOfMemoryError)的错误,而其他程序仍可以分配内存 。

CDC隔离

       CDC需要为本地方法支持java本地接口(JNI)。因此,CDC VM需要为每个本地状态或错误提供隔离。本地状态,我的意思是本地代码的全局和静态变量。本地错误包括那些残留在内存中的废指针,分裂的块(segmentation faults),非法的指令等等。

    掌握这些是在系统进程中隔离本地代码的唯一出路。。。对每一个程序。CDC VM做这些是完全正确的。它使用特殊的处理类型叉子(fork)来生产新的隔离。每个隔离运行在它们自己的进程中。CDC MVM当前仅仅在linux和solaris下可用,因为这有这些系统提供叉子(fork)兼容。Java级的隔离是进程自动掌握的。

    象DoS攻击应付资源缺乏,CDC VM应用系统去执行配额假如需要。这没有什么不同和本地程序对应资源缺乏的解决方法来说。

可靠的终止

CLDC 隔离终止

       CLDC MVM提供自己的线程库。当它需要终止程序时,它简单的选择不计划更多的程序,并取消所有的参考来隔离。因为所有的程序都是100%的纯java代码,它们的资源会通过垃圾回收(garbage collector)来清空。一些资源有本地副本,这些会被那些由GC触发的私有终结器(finalizers)来清空。注意:终结器不是CLDC规格的一部分。它是一个VM提供的一个被系统库使用的执行。

CDC 隔离终止

       CDC MVM里的隔离有自己的进程,终止是简单的杀死各自的进程。

效率

CLDC 普通资源共享

    CLDC MVM,所有的隔离作为线程运行在同一个物理VM,它们自动共享所有常量数据。这包括类的元数据(metadata)(比如常量池,属性),method bytecodes,ROMized对象和内部字符串。

    每个隔离从java堆中得到一个配额。通常,从java堆中分配的资源不是共享的。无路如何,这儿有更少的内部破碎因为分配的隔离来自同一个堆。

    开始一个新的隔离不需要VM完全重初始化。无论如何,系统库的类初始化需要重运行。

CDC 普通资源共享

       CDC MVM,隔离是从一个共同的进程分离(fork)出来的不同的进程,它们共享作为数据的只读内存页,不需要写入。CDC MVM采用几种技术来帮助系统最大化共享。

    在CDC MVM开始一个新隔离也不需要child VM完全重新初始化,但工作线程需要重生因为进程分离(fork)不和线程工作。象CLDC,类的初始化也需要重运行。

CDC MVM是真的MVM

       如果CDC MVM应用它的很多特性在系统进程,它和其他简单运行完整CDC VM的不同实例在进程中有什么不同?MVM被优化来允许有效的资源共享,但单个完整的VM做不到。这些优化也导致了一些性能上的开销但不会在单个完整VM上。什么?MVM有性能开销?为什么?是的,你想它会免费?你在2个隔离之间共享更多,开销也会更多。反过来也一样。但通常开销只有23%(如果我记得正确)。这可能或不可能成为你需要性能上的重要依靠。

       MVM和程序管理器一起来管理隔离,和单个完整VM运行在不同进程不一样,你有你自己的进程。

       在练习中,不是所有的隔离完全可用因为系统进程也会使用。比如,一些物理资源(硬件和系统)不能复制。因此,访问这些资源需要在隔离之间协调以至于它们不能相互一起。一个例子是绘画屏。Java类库(或他们的本地代码)需要修改来允许隔离间的协调。这个协调有程序管理器控制。

       物理资源的协调由CLDC MVM来执行。

我能在CDC中使用CLDC风格的MVM吗?

       技术上可以。。。但是这儿有个问题。CLDC风格的MVM不能做关于本地代码隔离的事情。那么,让我们看看我们只需要在环境中配置VM在我们保证那儿没有本地代码在程序中(或者我们拒绝有本地状态的程序)。那么我们能使用CLDC风格的MVM了吗?

       是的,但这儿仍然充满了附加的挑战。CDCVMCVM)运行在完全pre-emptive的本地线程上。调度程序在系统中,不是VM。因此,VM在线程调度上没有控制权(如果系统不提供这个机制。。。通常,他们不提供)。因此,近似于CLDC不能进行可靠的终止工作。

       我们还记得老的Thread.stop()API。但我们已经知道它有一个问题。但是,我们在这儿谈论的是100%的纯java代码程序。我们说我们不会让任何的本地代码运行。我们有CLDC风格的MVM来隔离java状态。这会让Thread.stop()的问题走开吗?现在让我们的任务终止?

       是的,我们可以让它工作。VM可以设置一个标志来在隔离中指出一个终止状态来终止。检查这个终止状态需要插入一系列的地方:VM InterpreterJIT编译器生产的编译后代码,本地代码中的循环。这些保证线程被终止

       在这些检查点,如果终止状态被检测到,一个未捕获的异常将被抛出。VM会忽略try-catch块当它出来这个异常。这确保程序不能捕获异常并防碍线程被终止。异常会导致java和本地堆栈展开。

       VM能够展开堆栈框架为java bytecode methods。但本地方法会要求本地方法检测异常并返回。因此我们不允许任何程序的本地代码,我们只在系统库中处理本地代码。每个本地方法会被修改来检测终止状态,确保它作为异常的替代返回

       另外,所有本地方法需要被检查以确保他们释放了所有的由他们方法中分配的资源。这些资源必须被清空在方法返回异常堆栈展开前。一些本地资源没有被分配和使用在一些本地方法。对这些类型的资源,我们需要确保他们同finalizer java对象的关联,因此他们能被取回当对应的java对象被GC时。

为什么我不能有自己的CLDC风格的MVMCDC

       你是不是感到疲惫?我们需要做这么多步骤为了在CDC中执行CLDC风格的MVM无疑是冗长的。现在考虑CDC库同CLDC库的复杂度和大小。因为所有本地库将被适当的修改来迎合CLDC风格的MVM正确的工作。这个执行努力是相当的高。风险也相当的高。

       另外,如果VM部署在一些中间设备堆(例如对机定盒的MHP中间设备),所有这些中间设备的本地代码也需要同样的处理来保证CLDC风格的MVM正确工作。

       因此,这个风格的MVMCDC来说执行难度是相当的高。Sun究竟有没有试验代码在CVM上来执行这种MMV。因为执行的花费和风险包含本地代码部分,这些代码从来没被完成。但是,它和快会被开原在下一个phoneMe Advanced版本,欢迎每一个感兴趣的人来完善它。

JavaSEMVM

       CDC风格的MVM可能或不可能在JavaSE中运用。这些VM的结构不同。但是,他们可能或不可能有利于这个途径。JavaSE VM的类共享特性已经是这个方向的一步了。

       CLDC风格的MVM。如果你明白它同CDC的不同,你可以看到它已经很大程度上接近JavaSE了。这是因为JavaSE有相当大的类库。但是,只有这些库中的本地代码会被贡献不同。幸好,JavaSE库的大部分是纯java代码,但这足够让这个任务较少的让人畏惧。

如果我不需要所有的隔离特性?

       CDC,你已经有命名空间隔离通过使用类装载器(classloader)。这儿有部署在基于同步线程和类装载器命名空间隔离的系统。但是,这些系统经受不同的缺点来自真隔离的。一个通常的抱怨是一个行为不当的程序能够坠毁整个系统,所有的程序都同它一起坠毁。

       已经有厂商提供MVM解决方案。我总是希望他们能做一些工作象Sun在分析问题,或者他们提供一部分的解决方案。但是我没有使用他们的VM,我不知道他们的MVM是怎样完成的。

这对你意味着什么?

我希望你现在理解这个令人畏惧的任务包含在建立MVM解决方案中。我明白当你需要MVM的时候它还不可用,知道去执行这个这是很困难的。

但是,现在java平台开源了,如果这些特性对你来说非常重要,请贡献在VM领域。如果我们为这个工作在一起一点时间,我们能让MVM更快实现。

祝有美好的一天!

2007年08月06日

   

Mark Lam has been a virtual machine engineer in the JavaME CDC team at Sun Microsystems for over 6 years. Before joining Sun, he was a real-time embedded systems developer for 6+ years, working on application frameworks, graphics systems, networking protocols, game development, and fault tolerant systems amongst other things, on devices ranging from 64KB 8bit uControllers to 32-bit RISC machines.

原文URLhttp://weblogs.java.net/blog/mlam/archive/2006/11/c_further_with.html#more

         我已经谈论过一些关于CVM的深奥的知识,并且我想是时候说一些真正的技术了。因此,我花了昨天大部分的时间来制作了一个关于CVM的结构图来向你展示它的结构,但它比我想象的要长。结果,昨天没有放上blog。今天有希望能把它完成,并在周一补写到blog。它看来像放在坚果里的CVM

       另外,我使用 InkScape 来存放我的CVM结构图,我不知道这是不是最好的,但它适合做这个工作。因此,我想我在这给一个说明万一其它人也在找这样的工具。我使用 InkScape 是因为我在SVG里渲染CVM结构图,因此我需要缩放它来匹配任意你需要的解决方案而不用考虑细节。但我也发现我的浏览器不能快速的显示SVG格式的图片(可能我没有导出正确的格式),如果有人发现你的浏览器不支持SVG格式,请告诉我,我会把它转成PDF格式。

       顺带说一下,我想感谢留言的2位朋友,这让我知道我没有对牛弹琴。

为什么用C来写CVM

       这是CC++之间的选择?像我在前面文章里指出的一样,CVM的体系非常匹配对象类。使用C++已经是一个选择。我们选择C的原因是因为C编译器比C++编译器在嵌入式领域有良好的实用性。我提醒你可移植性是CVM的一个主要目标,也是为什么它在嵌入式领域能够生存的原因。有代表性的,当硬件更新,它总是和C编译器一起的,而C++编译器可能会或者可能不会更新。我们希望Java平台能够在任何平台运行,事实上这和选择C是一样的。

       第二个要注意的地方, 我们发现一些C++编译器总是生成非常低效的代码在一个周期(23个周期),这对任何嵌入式软件都是不好的。现在,在你跳到结束前,我不认为C++原因本身是低效的。私下的,我是一个C++的爱好者,我知道它怎样让你写出真正一流和高效的代码(像计算编译器协作)。或者臃肿的代码。我的建议是在这个时候,一般的人们不要过多的关心C++在给了你多少的工具链(和C比)。不要说任何C++比其它好很多的话。事实上,C++有一个坏名字,我想这非常不幸。

       照顾好自己,7年前,CVM就决心做些什么。低效的代码生成在34年前被察觉,或许这些关于实用性和效率的问题已经被修复了。

       其它我想要说的关于便携性和性能的在下面

便携性的一个注解

       我在前面提过,CVM的代码是由在shared目录里最高的代码密度组织成的(相对于特殊平台)。给你一个特别的概念,在2003年,我们在shared目录和platform目录为动态适应编译(JIT)测量代码线作对比。在这种情况下,shared部分包括 RISC层在 portlibs 目录,开始共享代码的比率是80-90%,保留CPUOS的特别代码。大多数由汇编代码组成的非共享代码生成的特定CPU体系的常规程序。如果我们考虑VM空闲因素,这个对共享代码的比率会更高。我们没有实际测量这个,但如果我乱猜的话,我说他会上升到95%

       一个汇编程序非常小的子集作为编译器代码和VM休眠之间的过渡是非常必要的。保持所有的焦点在特殊CPU体系的优化上。一个好消息是,除了少量的粘合代码外,CPU特殊的优化代码都是可选的。这意味着你不需要为JIT执行所有的命令来保证操作的正确。代码的共享部分(小范围汇编代码)对性能的提升仍然有重大的意义(50~70%的提升)。附加的优化根据需要或VM开发者的时间

       另一个要注意的问题是关于CVM体系的。一个 VM开发者必须能够完成一个CVM的完全最小效果的移植,但仍然会得到许多性能上的原因。那么,如果时间允许,尽可能的调整和优化以得到附加性能的提升。这就是为什么我们大多数的更新和提升在用C写的共享代码中。

       提升仅仅是一个CVM build的解释(比如禁止JIT),它会带来少许的成就。这儿只有一个常规汇编程序需要编写。这个程序通常被称为“本地调用(invokeNative)”,它的责任是成为本地代码和解释器的粘合器。它的全名是“(CVMjniInvokeNative)”。在这儿有例子。如果你做linux移植(或其他系统),那么你会有个很好的开始。如果不是,你将执行HPI,但你可以使用其他已经存在移植的相关代码。

       总的说来,CVM容易移植不仅仅依靠减少必须进行的移植工作量。(共享代码对平台特殊代码的高比例),它的目标总是允许移植成就相对于现阶段。对开发者来说,为了适合开始时间它是很容易分离的。它总是增加系统的易测性。

性能的一个注解

       我的职业教育背景是硬件。因此,随时我听到的关于某些软件的创新都会让我开始提高系统的性能。怎样的软件能使硬件超过它现在的性能运行的更快?答案是未知的。

       任何软件能取得的最快速度是作为运行在硬件上的命令或限制。无论如何,硬件靠自己来提升性能不是那么容易的。他让软件指挥(direct)硬件来有效的工作。“指挥(direct)”翻译成管理成本(management cost),我们通常不喜欢为不必要的东西买单。因此,用软件来提升性能相对更好的硬件是一个很好的主意。这让我们花费较少的代价来取得更多的性能。

       管理成本(management cost)是影响代码的移植性和可维护性。代码的可维护性、易移植性这个话题不需要太多的解释对于那些每年有很多维护经费的开发者。

       CVM代码的可移植性、可维护性总是非常重要的。现在phoneMe开源了,每个人都能够贡献bug 修改(fixes)和增加(enhancement)。我想提醒大家代码需要坚持维护,这对每个人都非常重要。如果开源的一段代码没一个人能读懂是怎么一回事??这可能用密匙来加密。我说丢弃因为代码恢复往往是恢复甚至是有时作者已经通过。(完全翻不通:After all, how open-source is a piece of code if no one can understand it? It might as well have been encrypted with the secret key thrown away. I say thrown away because unmaintainable code also tend to be unmaintainable even to its creators once some time has passed.

       关键点是我们不需要牺牲可维护性在性能上。这是一个谬论,当我们不能在同一时间拥有高性能和可维护的代码。非常难得的是有异常在我们可维护的代码中。无论怎样,我们应该包含损害不至于通过基础代码影响本地化。(The point is that we shouldn’t sacrifice maintainability in the name of performance. It is a fallacy to think that we can’t have both high performance and maintainable code at the same time. Very rarely will there be an exception where we might have to sacrifice some maintainability. Even then, we should try to contain the damage so that it is localized and not wide spread across the code base.

       这是CVM的解释程序循环用C写而不是汇编的一个原因。这的确可以用汇编来写,但代价是巨大的,在你移植和维护的时候。在实践中,我们发现CVMC写的解释程序循环的效率和优化的汇编循环差别不大,但移植性和可维护性很好。

结束

谢谢大家听我讲了这么多,下次将介绍CVM的世界,子系统,数据结构,还有一张大图片

祝有美好的一天!

2007年02月08日

    Mark Lam has been a virtual machine engineer in the JavaME CDC team at Sun Microsystems for over 6 years. Before joining Sun, he was a real-time embedded systems developer for 6+ years, working on application frameworks, graphics systems, networking protocols, game development, and fault tolerant systems amongst other things, on devices ranging from 64KB 8bit uControllers to 32-bit RISC machines.
原文URL:http://weblogs.java.net/blog/mlam/archive/2006/11/when_does_javas_1.html#more

 在我关于性能的文章中有一个评论,问到:我想到关于设备日益强大的处理能力和更多的RAM的事实,我想什么时候才是JavaSE代替JavaME/CDC的最好选择?你需要多少的CPU,RAM,Cache?
 在我回答这个之前,我必须放弃一个我是一个工程师的,这对我的雇员,Sun,甚至是Sun的其他工程师是不必要的。基于这点,让我们进入这个问题吧。。。
JavaSE or JavaME
 最初的问题是基于设备兼容性和性能为依据的。这个问题有许多尺度比我们第一次看到的。这个问题基于规范,普遍存在的,可移植的,等等。让我们从显而易见的地方开始。。。
设备能力
 如果你的设备象一个桌面/服务器(象奔腾系列)建立在嵌入式的盒子里。那么,常规来看,JavaSE VM能够取得更好的性能。如果性能稍微差些,那么你的路就长了。我说奔腾系列仅仅是给你一个计算能力的比较。我不是说只有X86处理器。显而易见,JavaSE也为SPARC和PowerPC移植,他们有同样的规则应用在这里。
 设备性能不只是关于选择处理器。以PowerPC为例。它嵌入我们已知的许多桌面和服务版本。处理器核心是一样的(执行同样的代码),但他们的性能是不一样的。显而易见他们的时钟频率,高速缓存是不一样的。还有其他的硬件不同(例如主板等级)在性能上。高速缓存体系,2极缓存,主内存容量,内存速度,总线速度,内存和I/O体系,I/O处理器,MMU,DMA,TLAB size,辅助存储器(硬盘,闪存)等等。。。你的设备有这些特性的大部分,这样看起来JavaSE更好,反之亦然。
 仅仅是看下内存容量,我想JavaSE在10,100MBs,甚至GBs内存上典型的操作有同样的footprint。CVM的操作通常在10MBs以下。当然,这取决于你的应用程序在做什么(对JavaSE和CVM一样)。但这些数字给你一个想法。如果你的设备有16MB RAM,CVM可能是你最好的办法。如果你有32MB RAM,它只会得到一点的提升,这依靠你努力达到的程度。CVM对大多数嵌入式应用程序仍然是最好的办法。低于100MBs,它仍然是比JavaSE有希望的。如果设备有1G或更多,我非常同意JavaSE是更好的选择。
 对于高速缓存,这更难告诉我们。0~10 KBs于CVM匹配。10~100 KBs,仍然是CVM。如果高速缓存大于1MBs,你可以默认运行JavaSE。但这不意味这CVM不是一个更好的选择。
 对时钟频率,低于100MHz,CVM是你较好的选择。100MHzs~1GHz,仍然是CVM。超过1GHz,JavaSE是当然的选择。但Sun在不久前展示了这些,CPU性能不只是时钟频率(参考 CoolThreads)。因此,上面的数字相对的。事实上,上面我提到的所有方面只是基于我的经验的猜测教育。我们可以使用这些提示,但真实世界的案例是不同的,这就是上面给出的案例没有固定规则的原因。
 现在,我们来谈论这些显而易见的材料,让我们进入那些人们没有想到的。。。
嵌入式系统开发者注意
 嵌入式硬件常常需要下面的特性:便宜(成本方式,非品质),可靠的,可能滞后于技术发展水平曲线一点,不会太多。它需要便宜是因为目标消费者是平常的人。便宜意味着你能够卖的更多。可靠性是显而易见的,没有人想要一个不可靠的系统。另外,死机的蓝屏(从其他的计算机体验)接受的体验。在嵌入式设备,如果设备失败,人们会得到真的伤害或苦恼。基于这些,设备厂商小笔记簿会受到伤害。消费者期望系统没有异常的工作。The lagging(绝缘材料?)的曲线部分是大部分cost reason(成本?)。曲线的最新的边缘是非常昂贵的。太多的lagging是昂贵的,因为部分(它们的替代)很难找到。在曲线之后的痕迹有一点典型的收益。显而易见,它们不能应用于所有的嵌入式设备。但我的焦点在这个观点,异常的案例也会背离这个这个理由。
 因此,这对于嵌入式软件(包括JavaME)开发者意味着什么?
可移植性
基于技术曲线变化,硬件设备应注意升级老设备导致成本过高的。当然,升级也会带来对硬件性能有利的地方。有时候,升级不仅仅是替换CPU,它是全部体系的更换。
有时候,厂商会基于不同的性能提出不同的硬件等级。比如,低端和高端是2个不同的市场,这些设备不会总是建立在同样的CPU体系上。
这是为什么JavaME吸引人的地方(write once run anywhere)。但WORA依靠Java VM的移植。因此,VM的可以移植性是非常重要的。在这之后,开发成本和移植成果同样棘手。 它会使厂商想把这些都最小化。这也是CVM更适合的一个原因。我会在一系列文章中解释,CVM的体系对不同的平台来说更容易移植。这不是说JavaSE不能移植,只是它不太容易做到。我在前面已经指出,可以移植性来自于性能成本。尽管这些成本对大部分案例来说微不足道。这就是为什么CVM的性能在好的设备上比不上JavaSE的原因。相反的,JavaSE难以移植。CVM选择可移植性,JavaSE选性能。
普遍存在的
 普遍存在的,我没有提及那些支持java的设备作为在这个领域里使用它们的小组。在这个案例里,我会提及VM移植的实用性。这些都基于易于移植。因为CVM是容易移植的,它的移植可用性(CPU体系和OS平台)多于JavaSE。举个例子,像这写的,CVM移植到ARM,MIPS,x86,SPARC和PowerPC。一些消费者会把CVM移植到其他CPU体系。前面我们知道,JavaSE只移植到x86,SPARC和PowerPC。你选择一个源代码已经移植的可用VM。除非你自己想做移植。这是一个可选项(通常这个工程师的玩笑,因为你的工作多移植有影响),你必须花时间去将它做正确。因此,这需要依靠你的开发者的时间表。如果你选择作一个移植,CVM是一个值得关注的容易移植的选择,对于你想在短时间里得到正确的高可移植性。
 这是CVM体系对于多样的嵌入式系统便于移植的一个因素,这是必要的折衷。
符合目的
像上面说的,你需要基于你要怎样的java平台特性在你的设备上运行来决定。让我们看几个例子:
案例1:你的设备是x86的盒子,只制造很少的数量(10s~100s),你可以在它身上花大量的金钱。它有1G的内存,有硬盘存储器。它主要运行一个java程序。这个程序有很沉重的线程负担,高性能。这个程序有特殊的目的,只对于这个盒子。这个盒子不被期望运行其他程序,尽管你可以升级它来适应你的程序。那么你的选择是JavaSE。关键字是:桌面/服务器类硬件,高性能,特殊目的的软件。它不服从标准。
案例2:你的设备要卖上百万台。它运行在ARM处理器。32M RAM。只有非常少的高速缓存。基于JavaME CDC1.1它有自己的组件,有自己的规范,应用在一系列的市场。那你的选择是CVM。关键字是:便宜的设备,小或低的性能,需要适应CDC。
案例3:你的设备是服务器,需要运行JavaEE servlets,它要在同一时间提供1000个servlet。每个servlet需要运行它自己的进程,不是线程。Servlet自己有多个线程。Servlets被期望有短的生命期。性能是临界的。每个servlet操作一个来自网络的服务会话。服务是未知的(没有图形),不计算范围(没有太多的问题需要解决)。如果servlets没有及时响应,,使用设备的用户会苦恼,非常的苦恼。设备有4G内存,配置4个超级CPU,需要适应JavaEE。
显而易见的答案是。。。JavaSE?不绝对。这是为什么:JavaSE比CVM有大的footprint。JavaSE基本的footprint是20MB。CVM的基本footprint在2MB以下。每个servlet需要4MB的内存来运行。因此,运行servlet的一个JavaSE实例需要大约24MB的内存。每个运行servlet的CVM需要大约6MB。
如果设备任何时候都有4GB内存,它可以运行170个JavaSE实例,或者682个CVM实例。如果你不想处理硬盘内存分页,那么你想同一时间你可以响应1000个服务请求里的多少?
我不想回答这个。答案是你必须清楚你想的。显而易见,仅仅是考虑设备性能,你不能做出最好的决定。其他方面,需要解决适应JavaEE。CVM完全适应Java VM第2版规范。因此,你可以在它上面运行JavaSE和JavaEE。但不会增加CVM的footprint,它仅仅是2MB。是的,我没有说出JavaSE VM的footprint的具体数量。我的例子的人为的,但它不是一个不可用的。它解释了我观点,事情不总是像它看上去的那样。有许多的事情需要考虑,的确,硬件/设备性能是不最重要的因素。
这对你意味着什么
 好的工程实践总是你决定的指南。明白你需要的(你的程序要干什么),考虑所有的因素:设备性能,可移植性,普遍存在,适应性,还要其他我们在上面谈到的。

祝有美好的一天!

2007年01月30日

         Mark Lam has been a virtual machine engineer in the JavaME CDC team at Sun Microsystems for over 6 years. Before joining Sun, he was a real-time embedded systems developer for 6+ years, working on application frameworks, graphics systems, networking protocols, game development, and fault tolerant systems amongst other things, on devices ranging from 64KB 8bit uControllers to 32-bit RISC machines.
原文URL:http://weblogs.java.net/blog/mlam/archive/2006/11/performance_how.html#more

性能:太多的好事?
               这篇文章需要开发者有PhoneMe Advanced VM和J2ME方面比较深奥的知识。
              如果你已经看过了phoneMe Advanced VM的代码,你可能已经注意到许多函数和结构都是以cvm为前缀的。CVM是sun公司CDC VM的名称,而cvm作为前缀是VM代码(特别是全局函数和结构)的标准习惯。这是所有使用sun公司CDC技术工作过的人的普遍常识,但在这里我还是要强调一下。另外,我简单的以CVM来代替phoneMe Advanced VM。
现在让我们开始今天的主题。。。
性能
           通常,没有用户会抱怨,当他们的软件有很好的性能。无论如何,性能伴随着价格。通常,这意味着复杂的代码和更好的硬件。这还意味着需要更多的内存来运行软件。对JavaME VM来说,它的目标是资源受限的嵌入式设备。这是一个明确的关系。因此,一些性能上的工作需要合理的代价。这意味这平台开发者不能做所有他们知道的书本上的优化方法。
          这样说,我希望你知道我没有说这些是因为CVM的性能是窘迫的。直到我们吃的,CVM是这个领域最快的虚拟机,如果不是最快的,给你一个关于CVM性能的想法。几年前,我们把CVM同JavaSE1.3的基于SPEC JVM98子集的client VM进行了比较。我们使用子集是因为SPEC JVM98使用了已经从CDC移出的不受赞成的API。因此,我们做了一些内部“移植”对这个比较。这个比较在PowerPC,PowerMac和Solaris SPARC机器上进行。同JavaSE比,CVM显示了80%~90%的性能,只有10%的静态footprint。你应该知道这是老的数据。JavaSE已经有了很大的提高,CVM也是。注意:我仅仅是共享这些比较而给你一个JavaME能达到的性能等级的概念,我没有说任何关于哪一个VM更好。
         因此,当我们谈论性能的时候,人们首先谈论的VM的一个组成是动态适应编译。而作为JIT,下面我会围绕比较谈关于一些性能的事。我会接触其他非JIT相关但又重要的领域或主题
静态编译 VS 运行时编译
           一个最大的错误是,工程师会在JIT开始执行从其他编译课本来的优化而不做太多考虑。这些优化技术中的一些是意味深长的,而一些不是。有一点,课本经常教的是静态编译。JIT,在其他方面,是动态编译。这是JavaME的资源受限请求的要素。你可以在它们的属性中找到对比。下面是2中技术的比较:
Static compiler                                                                       JavaME JIT compiler
能提供少量内存给编译工作                                                   必须最小化或限制使用的工作内存
能够提供更多的时间和CPU周期给编译工作                      必须最小化或限制CPU的消耗
假设所有的方法在编译时都是可用的                                   只能工作与一个子集
编译所有的方法                                                                       只编译正在使用的方法。
必须编译所有类型的代码                                                   只需用编译通用的类型,让解释器处理那些不常见的实例
             注意,很多静态编译都假定更多内存和CPU资源的可用性。因此,他们的编译技术有很多相似的假定。明显的,这些技术的一部分不适用于JavaME。
                注意,尽管java平台是一个动态环境,可以期望部分代码在运行时下载。后期绑定是Java VM和语言的特点。 这不匹配静态编译的假定:整个应用程序代码必须在编译期可用。
JIT的能力让解释器处理不常用的案例的执行,同样也减少非紧急代码在资源上的消耗(在编译代码和编译footprint)
             批评家会说在我上面基于广泛性的表格里的需求,在今天的编译技术水平下不是真的。为什么,对的,我同意。我假设静态编译也来源静态链接。但记住,你的编译课本可以没有包括这2个中的任一个。我也使用静态编译的严格定义。例如:我认为它是编译静态代码。
真实世界的执行会加入一些能力,包括动态代码(可以下载),但这些不是严格的静态编译。这里的要点是你不必盲目的应用一流的编译技术。这些技术常常对不同的系统(这对类似于java的平台)做目标和最优化,因此他们可能不适合这里。
            人们可能有这样的误解,通过静态编译的代码要运行的比实时编译的要快。这不是全对的,实时编译的代码能够超越静态编译的代码。一个关键的原因是,java平台是动态并且后期绑定的。我会在以后详细的讨论这个。
           因此,有很多的原因导致静态编译不适用,甚至当你关心的资源和性能受限大打折扣。
JavaSE Hotspot VS CVM
        因此我们不能从编译器课本挖掘出诀窍。那从JavaSE VM可以得到诀窍吗?回答是“可能”。首先,这是资源受限的问题。JavaSE已经和有许多资源的大系统匹配了。这完全是合理的和可接受的,他们使用这些资源给你最好的性能在你的话费下。但当这些资源在你的设备上不可用时,这些技术可能就不能用了。
            另一点对普通开发者来说不是那些显而易见,JavaME 执行(像CVM)不仅仅是JavaSE的小版本。JavaSE目标设备的类型和JavaME有很大差别。CVM不是因为比JavaSE Hotspot少了一些功能而变小,CVM体系被设计的它可以工作在不同的嵌入式设备上。在它设计上的每一级,不同的选择会导致速度-空间的权衡。由于这个原因,用在JavaSE里的技术可能不能应用在CVM里,因为它们有不同的权衡。
                 给你一些例子来说明JavaME设备和JavaSE的不同,一段时候前,我的一个JavaSE方面的同事发现了当他应用一个可靠的技术来改善高速缓存位置,基于一个基准他能得到20%性能的提升。这抓住了我的注意。20%是不容忽视的,因此,我应用这个技术到CVM。令我吃惊的是,基于同样的基准,性能下降了70%,发生了什么?不同的是,JavaSE运行在一个有大量高速缓存(上百KB甚至是几兆)的服务器上。而我运行在只有32KB高速缓存的基于ARM处理器的设备上。这个改良的高速缓存位置在这儿制造了一个冲突。
 这个有效提升JavaSE的技术相对CVM来说,这也不是一个精确的例子。在这个例子里,他可以解决。但如果最优化代码,这项JavaSE技术可用于那些有着巨大缓存的设备?把这个技术应用在CVM实际上会造成那些没有大量高速缓存的JavaME设备性能的大幅下降。
              因此,关键是我们不要盲目的应用从JavaSE来的任何重要技术。注意上面的例子也说明了JavaSE VM运行的不比CVM快,当它运行在JavaME设备上时,即便你有大量的RAM(不是系统高速缓存)。这就像你想要你的汽车使用火箭引擎而有更大的马力。这听起来是一个不错的主意,但你的燃料系统不能支持它。结果也不比一般的汽车快。什么也没有改变。
              JavaME不仅仅是JavaSE的缩小版。对比JavaSE和JavaME就像对比苹果和橙子。
 基准
                 最后,确定优化是否工作的最好方法就是实验。 我们经常自己做这些事情。当一个念头失败,我们不混合基本代码。检测优化是否联合的一个重要的标准是,花费了多少成本在小组的资源分配上。另外,它带给了你多少性能的提升。
                 测量性能的提升,你需要运行某个类别的基准。一个常见的错误是人们运行了一个小的基准仅仅在测试一个优化提升的范围。真实世界的应用程序可能不只参加了一个循环和一个代码范围。因此,基于真实世界应用程序的基准是一个可靠的指示。对JavaMe来说,我们喜欢SPEC JVM98,但像前面说的,它不能不修改那些不赞成的方法而运行在CDC上。另外我们还喜欢EEMBC的GrinderBench。
               如果可能,运行你的基准在JavaME类型的设备上。就像上面指出的,JavaME不同于JavaSE,你改变在JavaSE类型的桌面或服务机器的的基准将给你指示,改变的结果是否有增长。但不同的JavaME设备,你得到的结果不完全一样,需要有适当的工程判断。
另外的性能
                一般的,java平台的性能不仅仅指执行引擎(解释器,JIT)。VM运行时和类库的品质也是游戏的一大部分。有些时候,它们甚至比VM重要。这包括主要依靠本地代码(相对于java代码)的graphics/GUI应用程序。无论如何,这不是意味着他们不依靠VM来运行。严格来说,VM运行时库是VM实现的一部分,我们也需要优化它。
                VM也能提供帮助机制使类库能执行的更好。他们需要共同工作。
               最后,有一件关于本地代码的事情。一些人认为他们的代码会执行的更快如果他们主要代码都是本地代码。这确实是个谬论,因为一系列的原因,使用本地代码确实会造成性能的下降比起一些功能使用java字节码。
               所有的这些都会在后面讨论。
这对你意味着什么
           性能是个复杂的主题。我们在这里仅仅是触及到了它的表面。正如我上面想要指出的,事情不是总想它们看起来的样子。当试着对JavaME系统执行性能提高的工作,对于嵌入式系统开发者来说,谨慎的思考是必要的。每一种优化技术需要在这个地方个别的进行评估。
            祝有美好的一天!:)

2007年01月25日

         Mark Lam has been a virtual machine engineer in the JavaME CDC team at Sun Microsystems for over 6 years. Before joining Sun, he was a real-time embedded systems developer for 6+ years, working on application frameworks, graphics systems, networking protocols, game development, and fault tolerant systems amongst other things, on devices ranging from 64KB 8bit uControllers to 32-bit RISC machines.

 原文URL:http://weblogs.java.net/blog/mlam/archive/2006/11/introduction_to_1.html

           如果你现在在阅读这篇文章,那么你对Sun通过PhoneMe工程来开放J2ME源代码有所了解,如果不是,点这里了解关于PhoneME。
一些背景信息
       开放我们代码的目的是允许你能够访问它,学习它,并有可能贡献你自己的改进。现在你已经可以访问一个代码链了,但访问和能够理解以及贡献有很大区别,它需要一些特别的知识。就大部分来说,只有Sun的雇员和少数例外(使用我们技术的公司的一些核心虚拟机工程师)能够这样做。我提到的知识包括:代码规范、术语表、设计原理、代码组织和设计权衡等等。但我相信你有足够的智慧来及时的领会这些,但我想这不是你在这个项目里开始的地方。
因此,我会就这些主题写一系列的文章(从这篇开始)来使我们的交流变的更容易,使每个人都能得到很到的资料而不用浪费时间在平常的事情上。我也会写一些像“怎样确定子系统的工作”之类的技术文章当我有灵感的时候。我允许你留下注释来告诉我你想我讨论的主题,或是你想我阐述明白的事情。在我选择文章主题的时候会考虑这些。
       在我开始前,你会问我如果来共享这些知识(为什么你要相信我的确知道我在谈论什么)。因此,关于我:工作在PhoeMe Advanced项目的虚拟机小组,负责建立和维护虚拟机。我从CDC1.0发布前就在这个小组工作。因此我和这些代码已经工作了很长的时间。在我们小组工作的过程中,我们不会正式的把虚拟机按我们工作的分成部分。我们基本会在任何需要的地方做必须的工作。因此,每一个虚拟机工程师的代码知识都是全面的。当然,我们每个人都有比其他人熟悉的领域。我需要指出我是一个虚拟机工程师(相对于类库工程师),我的专业技能集中在虚拟机和一些核心系统代码上。我也有一般的标准类库知识,但和他们比我不是专家。我们每个工程师都有自己的领域。因此我会写关于PhoneMe Advanced虚拟机的文章,因为这是我擅长的领域。
好的,让我们开始我们的第一个主题。
The meat(不知道怎么翻译了)
    前面,我说过深奥的知识我们会很少涉及,甚至在使用我们技术的用户里面。原因是这些用户很少有需要和动机去修改我们称作 共享代码 的部分。但现在这不会维持太久了。有太多的创新和特点需要在我们的代码里实现,这部分历史只限于Sun的雇员。我们的用户,在其他方面,需要关注的是我们称为 HPI (Host Porting Interface)的代码部分。点这里察看CDC移植指南,它会告诉你 HPI 的细节。实际上,在代码里有 HPI 文档如果你知道在哪能看到的话。你也可以从其他网页上找到一些有趣的文档。
设计原理(Design Philosophy)
       虚拟机被设计成高移植性,尽可能的减小代码以用于尽可能多的平台。这是虚拟机的基本规则。
    在共享机制下保证尽可能多的普通代码被减小。只有依靠硬件和OS的代码在共享代码以外。这些和硬件和OS捆定的指那些 目标或平台特殊的代码。点这里察看PhoneME Advanced src 列表。这有几个特殊的例子, arm ,linux ,linux-arm 文件夹。Linux 目录包含那些所有在linux移植下用到的代码。这个通常有一些 HPI 执行被调用,从 share 目录下。
     Linux-arm目录包含附加的用户定制的全部或重载的执行在linux目录。这些用户定制只能对于linux arm 移植。
     arm 目录包含针对arm的特殊代码,通常,他们看起来是一些有效函数(有些情况它们是汇编代码)。它们能被不同的arm平台移植调用。
     你在OS文件夹(如linux)下可以找到代码同等的共享文件夹(包括它们的子目录),紧随其后的是OS-CUP(例如: linux-arm)和CPU(如 arm)。这些事实表明了VM是多么的可以移植。移植成果通常只需要执行活修改目标特定的文件(这只是总代码里面的很小一部分)。
    我们工作的多数和共享代码里的创新对于目标特定代码只支持我们的决心来对所有移植平台最优化性能是相反的。这样,大部分性能工作都在共享代码里,这对每个移植都有好处。这样我们希望应用的特殊移植都被最优化。为了做到这点,我们常常把它们放在适当的OS-CPU或CPU文件夹下。
        我们代码组织的另一方面是代码维护以便于阅读。你会发现共享代码没有用 #ifdefs来定制不同的OS和CPU体系。你可以看到#ifdefs被enabling/disabling VM特性代替。你也可以看到OS,CPU和OS-CPU文件仍然易读,因为他们没有被#ifdefs用来和其他体系分开。
       在src文件夹,你可以看到portlibs文件夹。Portlibs被用来保存那些对多个移植来说通用的,但又不完全能以OS或CPU来区分的代码。一个例子就是工具链(gcc)或库/标准(posix,ansi)。多种的移植(OS和OS-CPU文件)可以选择使用portlibs里适当的代码。
       下面一个需要立即的概念是代码组织:根据OO术语,VM有一个父类。这个父类在共享代码里是明确的。每一个特定OS和CPU目标移植的VM是它的子类,通过继承来实现重用。OS代码是共享代码的直接子类。OS-CPU代码是OS代码的子类。CPU文件夹下的代码是可以被OS-CPU类选择使用的有用库。Portlibs 代码是OS-CPU类可以选用的另外的库
     总的来说,单个VM对一个给的的平台(OS和CPU)是incamated(这个词不知道什么意思)。无论如何,这是一个来自OS-CPU VM类的示例,它扩展了OS VM类,OS类又扩展了共享VM类。OS-CPU VM类也可以重用那些在CPU和portlibs里被授权的类。
      留意,这只是代码组织上的一个概念模型。你会发现在代码里的父和子VM没有参考。这个概念模型表明看来也不完美。你可以发现一些代码关联方面的范围不适合这个提取。是的,这是一个例外,但这个模型是一个普通规则。
这对你意味着什么
    当你计划寻找那些完成某些功能的代码,想想这些功能的属于(shared,OS,OS-CPU,or in the CPU or portlibs libraries)。这可以帮助你快速的定位你感兴趣的代码。
    你也可以对你想贡献的代码做同样的思考。这个代码组织是VM完成的一个关键因素,它便于移植(这是对移动和嵌入式领域的VM是非常重要的特点)。代码回顾过程对代码贡献也是必须考虑到的。
    正如我前面提及的,不遵守这些协定你可以得到一些例外。请不要使用那些偏离协定的借口。作为代替,这些已存在的异常会被相应的修正(如果可能)。或者有一个很好的技术理由,这些情况不适合希望的模型。如果理由充分这些异常是被允许的。
嗨,等一下
 所有那些关于可移植的部分听起来都是很好的,但是不是所有的这些层都在性能上有效果?回答是否定的!“不”是对那些我们担心的例子。是不是VM作为高执行蚂蚁它可以内联到任何地方,摆脱压条?可能不会,但我们在可移植和易维护中有一个折中。注意,在实践中,一些执行是可以被忽略的。这就是说,代码不被执行在本地路径。层使用了多样的技术来被执行(那些我在这不会深入)并防止不必要的执行降低与它有关的损失。当然,小组有一些度量来确保这些代码是有竞争力的。
 让我来说下其他问题:如果我们不试着挤出每一点可能的性能(因为我们必须权衡我们的设计原理),那么有多少性能是足够的呢?我会在下篇文章回答这个问题。
 祝有美好的一天!:)

            The article translate from Darryl Mocek’s blog. Darryl Mocek is a staff engineer for sun microsystems,Inc. currently working on J2ME CDC and related techonlogies. the URL is : http://weblogs.java.net/blog/darryl_m/archive/2006/12/phoneme_advance_1.html

           辛辛苦苦打了快一个小时的字,都写完了,结果Maxthon死机了,没上传气死了,不写了!

2007年01月23日

           The article translate from Darryl Mocek’s blog. Darryl Mocek is a staff engineer for sun microsystems,Inc. currently working on J2ME CDC and related techonlogies. the URL is : http://weblogs.java.net/blog/darryl_m/archive/2006/11/phoneme_advance.html

So, let’s begging…

      在这篇文章里,我们将会谈到 PhoneMe 高级工程的目录结构。当你读到这篇文章的时候可以通过这里的链接浏览源代码。你也可以加入这个工程来做这个。

      PhoneME Advanced的源代码从 components/cdc/trunk 目录开始。在 trunk 目录下有下面的目录:

  • build  包含 make 文件
  • src   包含源代码
  • test  包含测试文件

这是显而易见的。

      一旦你在 src 目录,你就在所有平台源代码的根路径上了。你可以注意到有一个 share 目录包含有一系列的硬件和操作系统目录。我们将在后面谈到它。这些目录包含了特定硬件和操作系统的源代码(除了 share 目录)。下面的 share 目录里包含了大多数的 PhoneMe Advanced 的代码

  • appmanager  包含应用程序管理代码
  • basis   包含个人基本描述的代码
  • cdc    包含个人连接设备的演示代码
  • classes    包含个人连接设备的代码
  • foundation   包含基础描述的代码
  • javavm     包含 cvm 的代码
  • lib         包含java 安全文件
  • native    包含共享的本地代码
  • personal   包含个人描述的代码
  • tools        包含工具

        这些所有的目录都可以有一个类别:基层的,个人的。在这里最典型的是 classes 和 native 目录。classes 目录包含了所有的java代码,native目录包含了所有的本地支持代码。native目录豪华 JNI 代码和那些需要用到的库,比如 Qt

        appmanager 目录完全由java代码组成,没有包含本地代码。 cdc 目录只包含了演示代码,lib 目录包含了2个 text 文件来描述和java 安全有关的东西,一个策略文件和一个安全文件。tools 目录包含java代码和本地代码,但现在的目录结构有稍微的不同,现在我集中在 profile 代码。

       classes目录下面,大部分是 java package的根。所以你在下面能找到 java/lang 目录。

        CDC profile 建立在其他部分之上。所以 personal basis profile 包含了基础profile,personal profile 又包含了personal basis profile。 在这些目录中,foundation profile 代码包含在 foundation 目录。personal basis profile 包含在 personal basis目录中。在这些不同的目录中你可以找到一些相同命名的profile文件。比如:你可以在 basis/classes/common/java/awt/toolkit 下找到 toolkit.java 。在 personal/classes/common/java/awt/toolkit 下找到 toolkit.java 。这说明他们是不同系列的 profile 文件。

          在 build 目录下,你可以找到和 src 类似的目录结构。一个 share 目录,它包含了跨越所有平台的 make 文件。特定的目录对应特定的平台,下面的 make 文件都是对对应平台优化了的。

    Now, java is open source! I’m interested how the j2me implemented on the different platform, So i will join this open source project, learning more and more about j2me. j2me open source are named phoneme (this link will redirect you to java.net ,and you can register first). you can find all reference in this site.  let’s go!

     always, play enjoys!

2007年01月22日

摘至IBM, 原文URL:http://www.ibm.com/developerworks/cn/opensource/os-linuxthinkpad/index.html?ca=dwcn-newsletter-opensource

 

级别: 中级

Nathan Harrington (haringtn@us.ibm.com), 编程人员, IBM

2007 年 1 月 15 日

通过修改内核以在受震动导致内核出现紧急情况时自动重置 Linux 膝上型计算机,让您的计算机处于受保护的状态。在内核空间和用户空间中实现震动检测算法,从而执行自动关闭并在特定动力条件得到满足时重新启动。

2003 年,IBM® 开始销售在商业操作系统中集成了加速度传感器及相关软件的 ThinkPad 膝上型计算机,以便在 ThinkPad 坠地时对硬盘进行保护。来自 IBM 和其他地方的富有魄力的计算机程序高手们已经为 Linux 内核开发了利用这些传感器的模块。膝上型计算机的屏幕显示方向、桌面切换、甚至是游戏控制和实时 3D 模型等特性均已实现。

2006 年中期,适用于 Linux 膝上型计算机的基于敲击的命令开始可用于用户空间 Perl 脚本(与内核空间中的基于 C 的代码相对),允许用户运行基于特定敲击序列的随机命令。本文描述了修改 Linux 内核以添加经常需要的功能的过程:对物理输入做出反馈。当 Linux 内核出现紧急情况时,用户可以震动计算机(或对膝上型计算机执行开发人员可配置的任意次数的物理移动),计算机将重置。

本文还介绍了在非紧急情况模式下执行正常关闭的方法。例如,如果用户不注意将计算机放在尚未拉好的计算机包中,则需要计算机检测到正常行走或开车的动作,并关闭计算机。

先决条件

硬件

许多在 2003 年以后(包括 2003 年)制造的 IBM ThinkPad 都配有 HDAPS 硬件。如果不能确定硬件配置,可以到 Lenovo 的 Web 站点中查看详细的技术信息。要运行以下代码,必须有 ThinkPad。某些 MacBook 配有加速度传感器及同样的通过内核访问这些传感器的通用方法。但是,此处的代码并未在 Apple 硬件上做测试,而是基于两个 IBM ThinkPad T42p 型号开发及测试的。有关如何查找在物理上支持膝上型计算机所需的 ThinkPad 硬件的链接,请参阅 参考资料

软件

本文假定您熟悉内核构建过程,并了解内核编译所带来的发行版间的不一致性。有关内核构建过程的简介,以及一些优秀的入门示例,请参阅 参考资料

从 kernel V2.6.15 起,HDAPS 驱动程序已经包含在 Linux 内核中。为了简单起见,请获取最新的内核程序。为了便于开发及管理,本文是基于 Fedora Core V5 开发的。下面用于设置内核构建环境的指导信息是专门针对 Fedora Core 的,但是一般原理适用于所有 Linux 发行版。


回页首

内核开发设置

内核配置、编译和测试

要修改内核,需要按照版本信息中的指导信息进行操作。打开 Web 浏览器并开始按照第 8.6 节:“Preparing for Kernel Development” 中的指导信息进行操作。执行到第 2 部分时,可能会在执行第二条命令 su -c 'yumdownloader --source kernel' 时遇到问题。如果该命令未能把 kernel-2.6.15-1.2054_FC5.src.rpm 软件包下载下来,请使用 wget 命令 wget ftp://ftp.linux.ncsu.edu/pub/fedora/linux/core/5/source/SRPMS/kernel-2.6.15-1.2054_FC5.src.rpm 来获取该软件包。

在执行步骤 5 时,请用 cp configs/kernel-2.6.15-i686.config .config 命令选择基本的 i686 默认配置。确保将 makefile 中的 EXTRAVERSION 部分从 -prep 更改为 -1.2054_FC5。用 make oldconfig 更新构建配置。然后用 su -c "yum install kernel-devel" 命令安装内核开发模块。该模块将用于编译紧急情况触发模块。

我们现在已经完成了 Fedora Core V5 Release Notes 文档中介绍的内核配置的相关部分。其余步骤都是所有内核构建过程通用的标准步骤。建议现在构建并安装新内核、模块和 RAM 磁盘设置以确保一切按预期运行。如果您对自己的新内核配置很有信心,可以跳过以下步骤并直接转到内核修改部分。

make 命令构建新内核。成功构建内核后,请用 su -c "cp ./arch/i386/boot/bzImage /boot/vmlinuz-2.6.15hdaps" 命令将其复制到 /boot 目录。您需要使用 su -c "make modules_install" 命令构建模块。最后一个构建步骤是用 su -c "/sbin/mkinitrd hdapsInitrd.img 2.6.15-1.2054_FC5" 命令为 HDAPS 内核创建 RAM 磁盘。用 su -c "cp hdapsInitrd.img /boot/" 命令将这个新的 RAM 磁盘复制到引导区。引导时,用以下行更新 grub.conf 文件:

清单 1. grub 配置

title Fedora Core (2.6.15hdaps)
    root (hd0,0)
    kernel /vmlinuz-2.6.15hdaps ro root=/dev/VolGroup00/LogVol00 rhgb quiet
    initrd /hdapsInitrd.img

修改 panic.c 和 hdaps.c

现在已经准备好开始一些可快速完成的内核配置。确保位于 ~/rpmbuild/BUILD/kernel-2.6.15/linux-2.6.15.i686 目录。一定要先包含 hdaps 模块作为内核的内置组件,从而准备好在计算机的运行模式中提供对各处的震动检查。

使用 make menuconfig 命令并选择 Device Drivers > Hardware Monitoring Support。键入 Y 以包含 Hardware Monitoring Support 模块,因为 HDAPS 模块依赖于此模块。滚动到清单底部,并在 IBM Hard Drive Active Protection System (hdaps) 条目的旁边再次键入 Y。退出菜单并保存配置。

打开 drivers/hwmon/hdaps.c 文件,然后将以下文本添加到 include 部分中:#include <linux/reboot.h>。并紧挨着 hdaps_read_pair 子程序后面添加下面的新子程序:

清单 2. 来自 hdaps.c 的完整的 panicShake 子程序

/*
 * panicShake - reboot the machine if shaken
 */
extern void panicShake(void)
{
 int ret, x, y; // return value and x,y from hdaps
 int int baseX = -5000; // off scale default values
 int baseY = -5000;
 int totalDev = 0; // running total of deviations from rest (shaking total)
 int devThreshold = 4000; // larger threshold for more shaking
 int dimShiftX = 150; // in case your users shake more in a certain dimension
 int dimShiftY = 150;

 while(1)
 {
  ret = hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
  if (!ret)
  {
   if( x != 0 && y != 0 )
   {
    // if its a successful read and not a zero read
    if( baseX == -5000 )
    {
     baseX = x;
     baseY = y;
    }
    if( abs(baseX - x) > dimShiftX || abs(baseY - y) > dimShiftY )
    {
     totalDev += abs(baseX - x);
     totalDev += abs(baseY - y);
    }
    if( totalDev > devThreshold )
    {
     printk(KERN_EMERG "ok, ok! you're shaking my substrate - restarting");
     emergency_restart();
    }
   }//if not a zero value
  }//if successful read of hdaps data

 }//infinite while

}//panicShake

震动检测程序就绪后,需要在系统出现紧急情况时调用该检测程序。打开 kernel/panic.c 文件,并在紧挨着 panicBlink 条件部分之前的位置上放置一个对 panicShake(); 子程序的调用。发出 make 命令。趁着对内核进行重新构建时,让我们复查一下震动检测代码。首先,设置一些变量:

清单 3. panicShake 变量

 int ret, x, y; // return value and x,y from hdaps
 int baseX = -5000; // off scale default values
 int baseY = -5000;
 int totalDev = 0; // running total of deviations from rest (shaking total)
 int devThreshold = 4000; // larger threshold for more shaking
 int dimShiftX = 150; // in case your users shake more in a certain dimension
 int dimShiftY = 150;
 

需要特别注意的是偏差阈值参数和空间移位参数。这些参数可能需要根据尝试检测的动作的独特性质做出调整。例如,如果感觉迫切需要像完成篮球传球动作一样震动计算机,可尝试减少 dimShiftX 参数以更轻松地检测垂直于计算机屏幕的动作。反过来,如果震动脉冲触发剧烈的锯齿状动作,则考虑减少 dimShiftY 参数,以便快速地检测平行于屏幕的震动并在发生进一步的损害之前重置计算机。

空间参数选择 150 及总偏差选择 4000 都旨在检测一般用户的典型震动动作。要立即响应输入,请尝试将空间移位参数减少到 10 或更少,并将总偏差参数减少到 10 或更少。这些值将导致其他类型的输入被立即识别出来,例如猛击键盘或拍打显示器外壳。

接下来,考虑无限循环语句和条件。

清单 4. panicShake hdaps 读取和基本设置

 while(1)
 {
  ret = hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
  if (!ret)
  {
   if( x != 0 && y != 0 )
   {
    // if its a successful read and not a zero read
    if( baseX == -5000 )
    {
     baseX = x;
     baseY = y;
    }

代码运行如下:其余时间里,从 Hdaps 传感器中读取当前加速度传感器读数。读数经常是不成功的或者两个值都等于 0,0,这是不能用的数据。需要避免这些虚假的 0,0 读数,来自传感器各个方向上的每 10 个读数中就会有一个读数是 0,0 —— 无效的数据,确实如此。如果是首次成功读取,则将基本参数设为第一个 x 值和 y 值。如果计算机被放在不平的表面(例如人的膝盖上)时发生紧急情况,这将允许我们更有力地检测震动或其他动作。

子程序的其余部分实现简单的震动检测算法。

清单 5. panicShake 震动检测

    if( abs(baseX - x) > dimShiftX || abs(baseY - y) > dimShiftY )
    {
     totalDev += abs(baseX - x);
     totalDev += abs(baseY - y);
     baseX = x;
     baseY = y;
    }
    if( totalDev > devThreshold )
    {
     printk(KERN_EMERG "ok, ok! you're shaking my substrate - restarting");
     emergency_restart();
    }
   }//if not a zero value
  }//if successful read of hdaps data

 }//infinite while

如果在任意方向上的空间移位大于我们先前设定的阈值,就按照两个方向上移动的量增加总偏差。然后将当前的基数设为现有的加速度级别。这样重复地重新初始化基数值要求用户持续超出空间移位值以增加检测到的总偏差。这允许用户在紧急模式下移动并存储 ThinkPad,从而安全地将机器送到系统管理员那里。如果仅需要侧立、倾斜和持拿 ThinkPad 以触发重新启动,请删除重新初始化设定。


回页首

测试 panicShake() 内核

要发动一种紧急情况,需要在内核中调用紧急情况子程序。创建以下 makefile:obj-m := panicCall.o,程序 panicCall.c 在编译时将使用该文件:

清单 6. panicCall.c 内核模块源代码

/*
 * panicCall.c - Instigate a kernel panic
 */
#include <linux/module.h> /* Needed by all modules */
#lincude <linux/kernel.h> /* Needed for KERN_INFO */

static char *pMesgStr = "PANIC SHAKE AND BAKE";

int init_module(void)
{
 printk(KERN_INFO,"panicCall module loaded\n");
 panic(pMesgStr);
 return(0);
}

void cleanup_module(void)
{
 printk(KERN_INFO,"panicCall module unloaded, beyond possible");
}

以超级用户身份用 make -C /lib/modules/$(uname -r)/build SUBDIRS=$PWD modules 命令编译 panicCall 模块。现在就有了一个可调用的模块可以使用 insmod panicCall.ko 命令触发紧急情况。如果还没有该模块则重新引导(以激活 hdaps 紧急情况下触发启用震动的内核),并运行 insmod panicCall.ko。应当会看到类似以下内容:

清单 7. 内核紧急情况堆栈

panicCall: module license 'unspecified' taints kernel.
Kernel panic - not syncing: PANIC SHAKE AND BAKE ACTIVE
 [<c011a32e>] panic+0x3e/0x174   [<f8a97017>] init_module+0xb/0xc [panicCall]
 [<c013050a>] sys_init_module+0x1382/0x1514   [<c0152413>] do_sync_read+0xb8/0xf3
 [<c012a17f>] autoremove_wake_function+0x0/0x2d   [<c01c0672>]
 	 _atomic_dec_and_lock+0x22/0x2c
 [<c0169c32>] mntput_no_expire+0x11/0x6d   [<c0102bc1>] syscall_call+0x7/0xb

现在拿起计算机,然后用力地晃动它,计算机将打印出 “shaking substrate” 消息并执行重新启动。如果您不希望晃动可能活动的磁盘驱动器,请以超级用户身份发出以下命令:

清单 8. RAM 磁盘创建和模块复制

mkdir /tmp/ramdisk0
mke2fs /dev/ram0
mount /dev/ram0 /tmp/ramdisk0/
cp /root/panicCall.ko /tmp/ramdisk0/
cp /sbin/insmod /tmp/ramdisk0/

现在有了将模块插入位于 RAM 磁盘的内核所需的两个文件。用以下部分更新 /etc/init.d/halt 脚本,将其放在刚好位于 fsck check 部分之下 halt execute 部分之上的位置:

清单 9. 修改 /etc/init.d/halt

echo "disks now mounted in readonly mode, spin down in 5 seconds";
/sbin/hdparm -S 1 /dev/hda
echo "spin down hda called, waiting 10 seconds";
sleep 10
echo "calling panic from ramdisk location";
/tmp/ramdisk0/insmod /tmp/ramdisk0/panicCall.ko

以超级用户身份执行命令 init 0 以将计算机转入关闭模式中。在调用关闭程序前,计算机将把紧急情况触发模块装入内核,并调用震动检测程序。如果在系统关闭时仔细听硬盘的声音,可以听到明显比以往更长的喀哒声,然后多普勒磁盘将随着机械臂逐渐下降的 “积载” 位置而降低并且磁盘旋转停止。再过大约五秒钟后,将从 RAM 磁盘执行紧急情况模块,而物理磁盘头仍停止不动。现在,您可以随心所欲地晃动 ThinkPad 而无需考虑磁盘的运行状况。


回页首

用户空间关闭和动作检测

很多 IT 管理员都十分怀念能够随时获知硬件物理历史记录的功能。使用同一个简单的震动检测算法、一个 Perl 脚本和一种监视策略,管理员将能够更好地跟踪硬件的状态。例如,使用下面的 Perl 脚本在计算机遭到用户震动时平稳地关闭计算机。根据用户对 ThinkPad 的操作发送一封电子邮件、闪烁 “ThinkLight” 或播放一个声音文件,这些都可以轻松地完成。

清单 10. 用于检测震动的 Perl 脚本,第 1 部分

#!/usr/bin/perl -w
# shakeShutdown.pl - shutdown (or other command) when the computer is shaken
use strict;
my $file = "/sys/devices/platform/hdaps/position";
my $baseX = -5000;
my $baseY = -5000;
my $totalDev = 0;
if( @ARGV != 1 ){ die "specify a threshold value" }
my $devThreshold = $ARGV[0];
my $dimShiftX = 150;
my $dimShiftY = 150;
while(1)
{
 open(HD,"$file") or die "can't open file";
  my $line$line$line$line$line$line$line$line$line = <HD>;
  chomp($line$line$line$line$line$line$line$line$line);
  $line$line$line$line$line$line$line$line$line =~ s/\(//g;
  $line$line$line$line$line$line$line$line$line =~ s/\)//g;
  $line$line$line$line$line$line$line$line$line =~ s/\,/ /g;
  my( $x, $y ) = split " ", $line$line$line$line$line$line$line$line$line;

正如您所见,初始的程序设置几乎与 hdaps 内核代码完全相同。正则表达式和 split 命令仅将 x 值和 y 值从 (5,4) 更改为 5 和 4。程序的其余部分实质上也是相同的:

清单 11. 用于检测震动的 Perl 脚本,第 2 部分

  if( $x != 0 >> $y != 0 )
  {
   if( $baseX == -5000 )
   {
    $baseX = $x;
    $baseY = $y;
   }
   if( abs($baseX - $x) > $dimShiftX || abs($baseY - $y) > $dimShiftY )
   {
    $totalDev += abs($baseX -$x);
    $totalDev += abs($baseY -$y);
    $baseX = $x;
    $baseY = $y;
   }
   if( $totalDev > $devThreshold )
   {
    print "threshold passed $totalDev\n";
    my $res=`/sbin/shutdown -h 1`;
   }
  }
 close(HD);
}

请注意 shutdown -h 1 命令。这将给用户提供 60 秒的时间更改方法并发出关闭中止。更改此命令以运行您最喜欢的邮件程序,用户滥用设备时可以让系统管理员知道此情况。将消息记录到系统日志中,或让 PC 扬声器发出声响以便对获得的物理输入发出即时用户反馈。用 perl shakeShutdown.lp 1000 命令运行脚本。偏差阈值变得更小,因为加速度传感器的每次读取间隔与内核空间的每次读取间隔比较而言减少了。

修改空间移位参数和偏差阈值可以提供有益的对内核空间外部的物理活动的额外监视。例如,要采集 “行走” 行为的数据,需要将空间移位参数设为大约 20,并将偏差阈值设为大约 5000。这将检测到大约 63 个双坐标轴空间移位,这与膝上型计算机在处于运行状态时被放在典型的单肩背膝上型计算机包中的情况一致。检测到这种长距离行走后(不同于从办公位置到会议室的短距离行走),计算机将进入关闭程序以避免过热,因为空气在背包中不流通。修改空间移位参数使其具有高灵敏度,任何较大的撞击、坠落或震动都会被记录下来。


回页首

结束语

通过使用针对用户空间和内核级代码的这些简单算法,现在能够检测、记录和响应来自用户的各种物理输入。使用这些代码示例,从根据连续的加速度计算出来的高度修改硬盘性能参数,到丈量从办公位置到会议室的距离,并将其用邮件发送给空间规划师,您都可以应对自如。

参考资料

学习

获得产品和技术

  • Fedora Core V5 发行版的内核中包括 hdaps。
  • 使用 IBM 试用软件 改进您的下一个开放源码开发项目,这些软件可以通过下载或从 DVD 中获得。

讨论

关于作者

 

Nathan Harrington 是 IBM 的编程人员,目前从事 Linux、WatchPad 1.5 和资源定位技术的工作。

摘至IBM。原文url :http://www.ibm.com/developerworks/cn/java/j-javares.html?ca=dwcn-newsletter-java

对于 Java™ 语言开发人员来说,信息过量是一个真正的问题。每个新入行的程序员都要面临一个令人畏缩的挑战:要进入的行业是一个具有海量知识的行业。要了解的东西简直太多了。对于有经验的老手来说,情况只有些微好转。知识量总在增大,仅仅跟上进度就是一个挑战。如果有一份专业人士必备的书籍和网站列表该有多好!本文就是这个列表。它包含了每个专业的 Java 语言程序员在书架或浏览器书签中必备的最重要的书籍和网站。

这些都是您书架上必备的书和应该经常使用的 Web 链接。时间是一项重要的资源,本文帮您回避那些分心的事情,把时间专注于最有益于您作为Java 语言程序员职业生涯的信息源。尽管有多少程序员就有多少他们最喜欢的参考资料,但本文收集的这些都是优中选优,来源于我书架上的私家珍藏和许多 Java 专家的推荐。

我考虑了两种组织这份参考资料列表的方法。我本可以通过主题领域来组织,这也许很有帮助,但主题列表很快就会变得不实用。相反,我选择了另一种方法:通过类型来组织,即书籍和 Web 站点。

总的来讲,有经验的老手们用 Web 站点来跟踪行业的走势。书籍、文章和论文有助于跟上潮流,但它们总体上更适合于基础学习。极富创造性的书籍偶尔会撼动一两个基础性的东西。这样的书也在本列表之列。

需要提出的一点警告是,专注于 Java 语言的书籍和 Web 站点数量巨大。您钟爱的未必在这份列表里。那并不意味着它们不好。它们只是不在这份列表里而已。可能是因为我还不知道它们。也可能是因为我不认为它们能够算得上是重要资源。不包含一些参考资料是一个评判问题,但如果不这样的话,您也许就要花几小时来拖动滚动条,还要花上成千上万美元来买书。如果您作为一个专业的 Java 程序员,有一些常用的优秀参考资料,一定要让我知道这些资料。这份列表一直都在更新中,您提出的那些也许就会被收录进去。

书籍

每个程序员都会有一些由于经常被当作专业资料参阅而磨坏的书。下列书籍应该是 Java 语言程序员的书架上必备的。书很贵,所以我有意将这份列表弄得很短,仅限于重要书籍。

Thinking in Java (Bruce Eckel)

Thinking in Java, 3rd edition (Bruce Eckel; Prentice Hall PTR,2002 年)
Java 编程思想:第3版 (陈昊鹏 等译; 机械工业出版社,2005 年)
Eckel 的书对于学习如何在 Java 语言环境中使用好面向对象技术极其实用。书中大量的代码样例解释了他所介绍的概念。文字出自一个并不认为 Java 技术总是正确答案的人,所以相当地实用。Eckel 具有多种语言的大量经验,还有用面向对象方式进行思考的扎实技能。本书将这些技能放到实用的 Java 语言环境中。他还在写一本新书,名为 Thinking in Enterprise Java

Effective Java (Joshua Bloch)

Effective Java: Programming Language Guide (Joshua Bloch; Addison-Wesley,2001 年)
Effective Java 中文版 (潘爱民 译; 机械工业出版社,2003 年)
本书是理解优秀 Java 程序设计原则的最佳书籍。大多数材料从其他的 “学习 Java ” 的书中根本找不到。例如,Bloch 书中关于覆盖 equals() 这一章是我读过的最好的参考资料之一。他也在书中包括了很实用的建议:用接口替代抽象类和灵活使用异常。Bloch 是 Sun 公司 Java 平台库的架构师,所以他透彻地了解这门语言。事实上,他编写了该语言中大量有用的库。本书必读!

The Java Programming Language (Ken Arnold, James Gosling, David Holmes)

The Java Programming Language (Ken Arnold,James Gosling,David Holmes; Addison-Wesley,2000 年)
Java 编程语言(第 3 版) (虞万荣 等译,中国电力出版社,2003 年)
这也许是能弄到的最好的 Java 入门读物。它并不是一个标准规范,而是一本介绍每门语言特性的可读书籍。这本书在严谨性和教育性方面权衡得很好,能够让懂编程的人迅速被 Java 语言(和其丰富的类库)所吸引。

Concurrent Programming in Java: Design Principles and Patterns (Doug Lea)

Concurrent Programming in Java: Design Principles and Patterns, 2nd edition (Doug Lea; Addison-Wesley,1999 年)
Java 并发编程—设计原则与模式(第二版) (赵涌 等译,中国电力出版社,2004 年)
不是每个开发人员都需要如此细致地了解并发性,也不是每个工程师都能达到本书的水准,但却没有比本书更好的关于并发性编程的概述了。如果您对此感兴趣,请从这里开始。Lea 是 SUNY 的一名专业程序员,他的和并发性有关的作品和想法都包含在了 JDK 5.0 规范(引自 JSR166)中,所以您大可放心,他所说的关于有效使用 Java 语言的建议是值得一听的。他是一个很善于沟通的人。

Expert One-On-One J2EE Design and Development (Rod Johnson)

Expert One-On-One J2EE Design and Development (Rod Johnson)
WROX: J2EE 设计开发编程指南 (魏海萍 译,电子工业出版社,2003 年)
对于刚接触 J2EE 的人来说,这是唯一的一本如实反映这项技术的书。本书收录了多年的成功经验和失败经验,不同于其他许多作者,Johnson 乐于将失败的经验公诸于众。J2EE 常常都被过度使用。Johnson 的书能帮您避免这一点。

Refactoring (Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts)

Refactoring: Improving the Design of Existing Code (Martin Fowler,Kent Beck,John Brant,William Opdyke,Don Roberts; Addison-Wesley,1999 年)
重构:改善既有代码的设计(中文版) (侯捷 等译,中国电力出版社 ,2003 年)
Fowler 写了几本现已出版的最流行的编程书,包括 Analysis Patterns。他的关于重构 的书是这一主题的基本书籍。重构代码是被程序员忽略的训练,但却是程序员最直观的想法。重构是在不改变代码结果的前提下改进现有代码的设计。这是保持代码整洁的最佳方式,用这种方法设计的代码总是很容易修改。什么时候进行重构呢?当代码“散发出味道”时。Fowler 的书里满是 Java 语言代码的例子。许多 Java 语言集成开发环境(IDE)(包括了 IBM 的 Eclipse)都将 Fowler 的重构包含了进去,每一个都使用他的重构名命名,所以熟悉如extract method 等重构方法还是很值得的。

Design Patterns (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides)

Design Patterns: Elements of Reusable Object Oriented Software (Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides; Addison-Wesley,1997 年)
设计模式:可复用面向对象软件的基础 (李英军 等译,机械工业出版社 ,2005 年)
这是一本在专业程序员圈子里更为有名的书,基于作者共同的绰号,这本书被认为是 “四人帮(GOF)之书”。模式是思考和解决普通编程问题时可以重用的方式。学习模式是一门学科。使用好模式(或知道什么时候 使用模式)是一项技能。忽略模式则是错误的。书中所有的例子都以 C++ 表示,但 Java 语言是从那里诞生的,让 Java 语言程序员由此联系到如何在 Java 语言中实现这些模式相对简单一些。熟悉模式并了解如何使用好模式使编程更加简单。这使得和其他程序员交流也更简单,因为在针对通用问题的通用解决方案中,模式是描述解决方案中彼此协作的大量相关编程概念的快捷方式。一些更为通用的方式,如工厂方法 则是普便存在的,甚至存在于 Java 语言本身。关于明智使用模式的这个主题,也可以阅读 Joshua Kerievsky 的 Refactoring to Patterns,该书称可以让代码来告诉您何时实现模式。

Patterns of Enterprise Application Architecture (Martin Fowler)

Patterns of Enterprise Application Architecture (Martin Fowler; Addison-Wesley,2002 年)
企业应用架构模式 (王怀民 等译,机械工业出版社 ,2004 年)
比起小型、一次性项目来说,企业开发当然代表了更大的挑战。那并不意味着企业开发带来的所有挑战都是新挑战。事实上有些时候,这项开发已经 是以前完成过的了。Fowler 做了很多个这样的项目。他的书提到了一些通用解决方案,并提供了关于使用、折中和可选方案的指导。Fowler 在书中包含了一些熟悉的模式,如模型视图控制器(MVC),他也提供了一些您也许不了解的模式,如处理 Web 站点上特定页面请求或行为请求的 Page Controller 模式。正如您对待大多数模式一样,一旦您读过许多模式,您就会认为 “我已经知道那个模式了” 。也许是这样,但有一个用来引用模式的通用表达方式还是很有帮助的。在有多个组件(由不同人开发)的大型项目中,该类引用是一项很好的帮助。

UML Distilled (Martin Fowler)

UML Distilled: A Brief Guide to the Standard Object Modeling Language (Martin Fowler; Addison-Wesley 2003 年)
UML精粹:标准对象语言简明指南(第3版) (徐家福 译,清华大学出版社 ,2005 年)
对于专业的程序员来说,UML 是一门很重要的通用可视化沟通语言,但是它被过度使用和草率地滥用了。您无需对使用 UML 沟通了解太多。Martin 对 UML 的提炼为您提供了最核心的东西。事实上,前后的封页提供了常规基础上可能使用到的所有东西。该书中 UML 例子的代码都是 Java 代码。

Test-Driven Development: By Example (Kent Beck)

Test-Driven Development: By Example (Kent Beck; Addison-Wesley 2002 年)
测试驱动开发(中文版) (崔凯 译,中国电力出版社 ,2004 年)
测试优先编程将使编程发生革命性变化,能助您成为更好的程序员。在写代码之前编写测试开始很难,但却是一项威力强大的技能。通过优先编写测试,可使代码更加简单,并确保从一开始它就能工作(Beck 实践着他提倡的测试优先,与人合写了 JUnit,这是 Java 语言最流行的测试框架)。Beck 的书是权威的参考资料,扩展了的 Money 例子也用 Java 语言写成。Beck 详述了如何用测试优先进行 思考(这也许是许多程序员首先遇到的障碍)。

The Pragmatic Programmer: From Journeyman to Master (Andy Hunt and Dave Thomas)

The Pragmatic Programmer: From Journeyman to Master (Andrew Hunt 和 David Thomas; Addison-Wesley 1999 年)
程序员修炼之道——从小工到专家 (马维达 译,电子工业出版社 ,2004 年)
做一个纯粹的面向对象开发人员有其优势所在。在当今复杂的社会中,作为 Java 语言开发人员,为完成任务常要妥协。Hunt 和 Thomas 探讨了如何不将真正重要的东西妥协掉而完成任务。这不是一本关于 Java 语言的书,而是 Java 语言开发人员重要的思想读物。例如,我认为没从“要解决问题,而不是推卸责任”这句忠言中受益的程序员,不能像个自豪的艺术家一样在他的杰作上签上大名。

Peopleware: Productive Projects and Teams (Tom DeMarco and Timothy Lister)

Peopleware: Productive Projects and Teams (Tom DeMarco,Timothy Lister; Dorset House,1999 年)
人件(第2版) (UMLChina 翻译组 译,清华大学出版社 ,2003 年)
这份列表中的其他所有书籍都至少和技术有些相关。这本书却不是。在所有技术行话和首字母缩略词的海洋中,有时软件开发人员和经理们会忘记:是 制造了软件。DeMarco 和 Lister 向我们提醒了这一事实,也向我们提醒了形成这一区别的原因。这不是一本关于一门特定编程语言的书籍,但却是每个 Java 语言程序员都应该读的书。关于 “累死程序员如何让经理们适得其反” 还有许多其他的好书,但这是最好的一本。


回页首

Web 站点

Web 站点的数目浩如烟海,如果您想要消化其中的内容,穷毕生之力也难以全部访问。包含 Java 语言某方面内容的详尽的网站列表会大得离谱。下列站点都是可靠、真实的。

Sun 的 Java 技术站点

Sun 的 Java 语言站点
这是 Sun 的 Java 语言主站。作为 Java 语言开发人员,您会发现自己频繁地访问此站点。下列链接特别重要,特别是对新入行的 Java 语言开发人员:

  • New to Java Center
    New to Java Center
    New to Java Center 存放了许多循序渐进的 Java 技术资源链接。如果您刚接触这门语言,这是一个好的起点。
  • 教程和代码库
    Java Tutorial
    这里有大名鼎鼎的 Java Tutorial,以及关于 Java 语言各个方面(例如 Collection)的其他教程。

 

IBM developerWorks

IBM 的 developerWorks
推销自己也许有些厚脸皮,但 developerWorks 是一项巨大的资源,收录了大量 Java 语言工具和技术的教程和文章。其内容从初学者指南到学习这门语言到高级并发性技术。可以根据主题搜索内容,然后根据类型浏览。

Apache Software Foundation

Apache Software Foundation
Apache 站点是许多可重用库(通用领域)和工具的主页,这些库和工具帮助 Java 开发人员进行开发。这里的内容全都是开放源码,所以尽管下载想要的吧!许多极其流行的 Java 语言库和工具(如 Struts、Ant 和 Tomcat)都始于 Apache 项目。Jakarta 专区汇聚了大多数新兴的 Java 语言材料。

Eclipse.org

Eclipse
有几个好的 Java 语言集成开发环境(IDE)。Eclipse(来自 IBM)是最新的 IDE 之一,它很快成为 Java 语言开发的首要 IDE。它完全是开源的,这意味着它是免费的。该站包含了学习如何有效使用 Eclipse 的各种参考资料。这里还有关于 Standard Widget Toolkit(SWT)的信息,SWT 是相对于 Swing 来说更加轻量级的选择。

Eclipse 插件中心和 Eclipse 插件

Eclipse 插件中心Eclipse 插件
Eclipse 基于插件架构。事实上,插件是 Eclipse 的 Java 语言开发组件。但有差不多上千个插件,从 Web 开发的插件到在 Eclipse 环境中玩游戏的插件。这两个站点分类列出了大多数插件,可以进行搜索。它们是很棒的资源。如果您想在 Eclipse 开发环境中弄点新东西,幸运的话有某个插件可能已经实现,从这两个站点能找到想要的插件。这两个站点都允许评论插件,这样您就可以知道哪些插件好,哪些值得一试。

JUnit.org

JUnit.org
Junit 是 Java 语言中一个基本的单元测试框架。该站点包含了 Junit 最新最棒的版本,外加大量有关测试(Java 语言或者其他语言的)各个层面上(针对桌面应用程序、Web 应用程序、J2EE 应用程序等)的其他资源。如果您想找测试资源,这里就是最佳起点。

TheServerSide.com

TheServerSide.com
如果您要(或将要)从事服务器端 Java 语言的开发,此站点是一处举足轻重的资源。您可以到这里找到有关 JBoss、J2EE、LDAP、Struts 和大量其他主题的文章,并且都是完全可检索的。这些文章不仅仅是简单描述 Java 语言的特征或者支持的库。它们更进一步地描述了库的新奇用法(如使用 Jakarta Velocity 作为规则引擎,而不是模板引擎)。它们也提供了有关 Java 语言现状的连续评论(当前的一篇文章是由 Tim Bray 所写的 Java is boring )。该站点更好的通用功能之一是对 Java 语言工具和产品(应用服务器等)的矩阵式比较。

Bruce Eckel’s MindView, Inc.

Bruce Eckel’s MindView, Inc.
Eckel 写了几本 “用 …… 进行思考” 的书,内容关于 Java 语言、Python 和 C++ ,当我学习 Java 语言时,他的 Thinking in Java 对我尤其有帮助。它很实用并切中要害,在“在 Java 语言环境中如何面向对象思考”方面具有卓识。您可以从此站点免费下载他所有书籍的电子版。他也写了许多好文章,并且他把这些文章的链接都放到了这里(包括关于 Jython、Java 和 .NET 比较等内容的文章)。

ONJava.com

ONJava.com
O’Reilley 历年来出版了一些有关编程语言和工具的优秀书籍。他们的专注于 Java 语言的网站也不错。它有些有关各种 Java 语言工具(如 JDOM 和 Hibernate)、Java 平台(如 J2SE 和 J2EE)不同领域不同部分的文章。全部都可以被检索到。他们有优秀的文章和教程。该站点按主题排列。例如有 Java 和 XML、Java Security、Wireless Java 和 Java SysAdmin。该站点也有到 O’Reilley Learning Lab 的链接,在那里您能获得在线参考资料(Java 语言相关和其他的)。那些不是免费的,但是许多都面向大学认证。因此您可以以一种很方便的方式来学习技能,并得到一些认证。

java.net

java.net 社区
java.net 社区有多个“社区”,有特定于主题的论坛和文章。例如 Java Desktop 社区有各类与 Java 语言桌面开发相关的资料。Java Patterns 社区作为一个门户,也许对提供 Java 语言的模式资源相当感兴趣。还有一个 Java User Groups (JUG) 社区,在那里能找到有关创建、加入和管理一个 JUG 的信息。


回页首

结束语

任何 “好的”、“关键性的” 或者 “重要的” 参考资料列表都注定是不完整的,本文的列表也未能例外。 Java 语言的书籍数目众多,当然,万维网也很庞大。除本文所列的参考资料之外,还有很多用于学习 Java 语言的参考资料。但如果您拥有了这里所提到的所有书籍、网站、文章或者教程,您应当已经拥有了一个使您良好开端并助您登堂入室的实用宝库。

最后,要成为一个能力日增和高效的 Java 语言开发人员,方法就是用它工作,动手来尝试。如果有一个教程详细介绍了所需创建的软件的每一部分,您很可能并没得到多少好处。有时,您可能得走自己的路。在成功地尝试了一些新的东西之后,您可能想要写一篇文章、教程或者一本书来分享您所学到的。

参考资料

关于作者

 

Roy Miller 是一名独立软件开发培训师、程序员兼作家,他在充满挑战、快节奏的咨询公司里从事了十多年软件开发和项目管理工作。他最初在 Andersen Consulting(现在是 Accenture)公司工作,在那里,他管理团队实现了许多系统,从主机记帐系统到星形模式数据集市。最近三年来,他在北卡罗来纳州 Holly Springs 的 RoleModel Software, Inc. 公司工作,在那里他专业地运用着 Java 技术,并担任开发人员兼 Extreme Programming (XP) 培训师。他与人合著了 Addison-Wesley XP 系列的 Extreme Programming Applied: Playing to Win 一书,最近他写了 Managing Software for Growth: Without Fear, Control and the Manufacturing Mindset 一书,来帮助经理和管理层理解:像 XP 这样的敏捷构建方法为什么比传统的方法更有效。2003 年,他创办了自己的公司:The Other Road,该公司帮助其他公司了解如何向 XP 和被他称为 Extreme Business (XB) 的方法转换。