2009年04月09日

    最近突然又回到了“混吃、等死”的状态。也不知道是为啥子?难到说到了一定的年龄就容易有这样的状态?!难道是因为最近工作轻松?我想可能有一部分原因在这上面,做现在这个维护项目有一年多了,不能说对相关的知识都烂熟于心,但可以说比较熟悉。这好像就直接导致没有继续学习的动机,而且需要维护的事情也比以前少了不少,加之现在有部分管理的工作,对项目的学习就没啥兴趣了。
    哪还能做点啥喃?学习其他的,Maemo,QT?有兴趣,最近也一直在学,但老实说,和项目没有直接关系的东西要学习的话只能是利用非工作时间,非工作时间又能有多少可以安排在这些领域的学习上呢?英语要不要继续学喃?要!这么学?对我来说看片是最好的方式,好像既又休息了又顺便练习了听力,但这样的话成长是很缓慢的。聊胜于无吧!
    最近一直比较想找机会到国外去工作一段时间,半年或者一年。但金融危机下,公司的这种机会大大缩水,而且要配合到现在项目的时间。难啊!关注吧。。。学习吧。。。等机会!希望金融危机早点过去,这样大家的机会才多!前提是大家在这段时间抓紧时间充电啊!

2009年03月25日

Introduction     

When developing for Symbian OS you might have experienced numeric error codes or panics of some sort. Usually you would have to look up the description by manually searching the Symbian documentation, which can be cumbersome and time consuming.

This time is over! Now you will automatically get the panic description to any panic that occurred in the emulator displayed right within Carbide.c++. You simply have to add the PanicLookup plug-in to Carbide.c++ and it will automatically detect any panic that occurs. There are no compromises; you will see exactly the same description that is available in the Symbian OS 9.3 System Panic Reference.

You might ask what will happen if you experience a panic on one of your test devices or one of the standard Symbian OS error codes. No problem! Just enter the panic type and number or the error code into the plug-in’s text field and the description will be displayed. Even better, PanicLookup supports an auto complete feature, which considerably speeds up entering panic codes. Additionally, you can hit TAB once the right panic type is suggested to directly jump to the panic number to save even more time.

 Installation

Extract the plug-in (fhhgb.carbide.paniclookup.1.0.0.jar) to your Carbide.c++’s plug-in directory (e.g. C:\Program Files\Nokia\Carbide.c++\plugins). Launch Carbide.c++ and go to "Window -> Show View -> Other …". Choose "Panic Lookup" from the list and click OK. In order to take advantage of the automatic detection feature, you have to turn on epocwind.out logging (Emulator: "Tools -> Preferences -> C++ Debug -> Enable EPOCWIND.OUT logging").

download link: http://www.symbianresources.com/projects/paniclookup/PanicLookup.zip

2009年03月20日

1.成都到犍为,石羊场车站。每25分钟一班,票价52。大约2.5~3小时到达犍为。
2.犍为中心车站下,然后坐(犍为-三井)的班车,到石溪下。石溪是小火车的起点站。PS:三井就是嘉阳煤矿集团的3号井,
现在也是煤矿的行政办公中心。下面是小火车的时刻表:

    石溪站    芭沟站    黄村站         石溪站
     6:00     7:10       7:25           8:30
     9:30     10:40     10:55          12:00
    14:00     15:10     15:25          16:30
    17:30     16:40     16:55          20:00

小火车线路:石溪-跃进-蜜蜂岩-菜子坝-焦坝-芭沟-黄村
小火车价格:旅游车厢20元往返,普通车厢10元往返。需要注意的是小火车到黄村后会马上返回,每个站的停靠时间很短。

PS:小火车在蜜蜂岩会换车头。芭沟是最后一个有人居住的站。黄村是以前的一号矿井。

吃:犍为有家核桃树来凤鱼不错,来凤鱼其实就是冷锅鱼。学府街是犍为的好吃一条街,选择很多。鸡血旺煲可以尝尝。
住:小旅馆的价位在30~50/床。80就是标间了。

2009年03月17日

细节请看下面的网址: http://www.martin.st/symbian/

个人觉得这个其实没太大的用处。symbian的开发还是在windows平台好了,如果喜欢linux平台,不如关注Maemo平台和QT算了。

2009年01月24日

pre:  you should login the scratchbox. goto your project folder

1. ./autogen.sh
2. ./configure
3. make dist             // to make a *.tar.gz file.  * manes your package name
4. mkdir ../packaging    // make a folder that we package debian in it
5. cp *.tar.gz ../packaging
6. cd ../packaging
7. tar xzvf *.tar.gz
8. cd *                  // * manes your package name
9. DEBFULLNAME="User Universal"  \
 dh_make -e user@maemo.org -f ../*.tar.gz
10. cd debian
11. cat ../COPYING > copyright   // use your copyright replace with default
12. rm *.ex *.EX dirs docs README.Debian
13. change control file to match your mind.   // it’s very importance
14. dpkg-buildpackage -rfakeroot    // Generate the debian package
15. fakeroot dpkg -i *.deb  // install the debian package to Maemo Simualtor
16. fakeroot dpkg –purge *  // * means your package name

 

2008年02月26日
     22号到北京芬兰大使馆去申请90天的商务签证了。比想象中的简单、快!签证的人很少。签证处有2个中秘窗口,2个面试窗口,一个财务窗口。给中秘递上资料,然后交钱,等了10分钟左右,签证官面试,问了些常规问题,主要就是看和资料上写的是否一致,大概4,5分钟就完了。感觉也没什么,这主要是和前美国比,最近公司有几个同事在成都美国领事馆签美国,都被拒了。其中有人被拒的理由是:在公司服务时间太短。看来美国签证的确难拿啊!!想到年前intel的朋友去美国开年会,他的同事也有被拒的,心里也就想的通了,连intel这样的美国大公司的员工都拒了,什么都有可能了。
     美国真的就那么好?比欧洲国家好?
2007年12月27日

最近在IBM的网站上看到一些有趣的东西,链接如下,方便自己以后查找

http://www.ibm.com/developerworks/cn/linux/l-lob800-1.html?S_TACT=105AGX52&S_CMP=NL&ca=dnl-cn-12192007

2007年09月11日

    Jiangli Zhou joined Sun Microsystems in 1999. She has been in the J2ME CDC VM (CVM) team since 2000. Over the years, she has worked on various areas in the VM, including ROMizer, classloader, JIT compiler, etc. Her latest interest is supporting Mobile Information Device Profile (MIDP) on CDC..

原文URLhttp://weblogs.java.net/blog/jiangli_zhou/archive/2007/04/cvm_bootstrap.html

         你可能已经知道CVM是用C写的了。因此,VM启动后发生了什么?在你的main()函数中执行的第一行java代码是什么?这在启动期间是一个连续的过程,我们通常叫这个为启动过程(bootstrap)。这篇文章将解释CVM启动过程和初始化过程的详细情况。

    CVM启动代码是ansiJavaMain()(ANSI适应),它被Cmain()函数调用。ansiJavaMain()做的第一件事转换和预处理VM的参数。因此,它调用JIN_CreateJavaVM()(定义在JNI Invocation API)来创建和初始化CVM。在整个过程中,它初始化所有的VM全局状态,包括系统互斥量(system mutexes),java heapthreadsclassloaders,等等。在VM创建成功后,它装载java程序的主类并调用javamain()方法。

预装载初始化

       CVM支持在编译期间类的容量控制(ROMization)。它通过VM装载和连接类数据。我们有时候叫它类的预装载。这些事情中,首先需要做的是初始化容量类(ROMized class)。每一个容量类块(CVMClassBlock是关于存储java class的远数据中的主要的数据结构),它发现相应的java实例并初始化它们通过填入它们类的块指针,类装载器指针等等。它重申压缩的字符串数据和结构来匹配java实例通过填入字符串值,偏移量和长度等等。注意容量类(ROMized class)不能在java heap中生存。

       CVM中,方法数据结构(CVMMethodBlock)由可变的和不可变的部分组成。不可变部分包括方法名和类型id,方法表的索引等等。一旦被JCCROMizer)或类装载器初始化,它们的区域就不再可写入。可变部分包括调用者指针,编译后代码开始PC等等。作为预装载器初始化的一部分,VM初始化方法数据为每一个容量可变类通过拷贝不可变部分并填入可变部分。

系统互斥量初始化

       象一篇Mar Lamblog一张大图片(CVM地图)CVM有全局互斥量来控制VM子系统的同步问题。这包括JIT锁定,heap锁定,线程列表锁定,类表锁定,装载器缓存锁定,全局根锁定,不牢固的全局根锁定,类型id锁定等等。在整个启动过程中,CVM创建和初始化这些全局锁定。

初始化GC全局根堆

       CVM初始化GC根堆,包括全局根堆(分配JNI全局参考和CVM全局根),不牢固的全局根堆(分配JNI不牢固全局参考),类全局根堆,类装载器全局根堆,保护域全局根堆,类表根堆(所有动态装载类)。全局根堆被GC使用来扫描活动对象。

类型id系统初始化

       VM做的下一个事情是初始化类型id系统和注册一些通用的类型id,比如<init><clinit>,在CVMglobals中的<finalize>。为了防止在运行时重复查找这些类型id

类系统初始化

       下一步是类装载器缓存初始化。装载器缓存被用来缓存所有的<Class, ClassLoader>对,当它们在系统中被装载的时候。

初始化java heap

       CVM使用-Xms, -Xmn, -Xmx选项来规定开始时的最小和最大heap size。它通过VM参数来解决这些大小信息,分配heap的开始大小。Heap可以在运行时增加到最大。

预分配对象监视者和异常对象

      VM创建一个初始数量的对象监视者。这是VM知道的需要的最小数量。异常对象包括OutOfMemoryError, StackOverflowError等等。当没有可用内存的时候根据需要创建异常对象。

JVMTI初始化

       如果支持调试,CVM也做 JVMTI的相关初始化。

JIT初始化

       如果支持运行时编译,CVM需要做 JIT的相关初始化,包括初始化编辑策略,编译器后端,代码缓存等等。

初始化一些系统类

       一些容量可变的系统类需要被VM明确的初始化。首先,它初始化这些系统类不需要线程支持来执行这些静态的初始化。它们包括 java.lang.Class, java.lang.String, java.lang.Shutdown, java.lang.ClassLoader等等。它会创建系统ThreadGroup,ThreadGroup,主Thread对象。在这些线程初始化后,VM调用System.initializeSystemClass()来设置系统属性,stdinstdoutstderr。在这个过程中,它还创建了:

1、  一个参考句柄线程,它询问为决的参考

2、  一个完成器线程来运行完成器。

解析参数

       VM调用sun.misc.CVM.parseCommandLineOptions()来解析其他的参数。在这个过程中,它可以添加用户定义的属性,找到主类名。

       现在,CVM准备好了,为了执行main()函数,首先它需要找到java主类。为次它创建一个系统类装载器(sun.misc.Launcher$AppClassLoader)并用类装载器搜索和装载主类。当类被成功装载,它调用main()方法并开始执行java代码。

2007年09月03日

 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/cvm_stacks_and_1.html

         欢迎继续讨论phonME Advanced VM(CVM)的内部联系。如果你错过了开始的讨论,你可以在这儿看到我通过CVM地图来对VM主要的堆数据结构的一个介绍。今天,我们会深入到java方法的执行和它们在运行时堆中的表现。我说的这个堆是线程里面用来记录活动方法的堆。不是包含APIAPI层的堆。这次的讨论会给你洞察CVM里面java代码执行的控制流(比如任何时候谁拥有CPU)。所有的代码都可以在phonME Advanced的工程文件夹下的src/share/javavm/includesrc/share/javavm/runtime找到。

执行引擎

       CVM中,有一个解释器,一个动态编译器(JIT)。从概率上来说,解释器就是一个大的switch声明。每一个case对应一个bytecode用来执行(在executejava_standard.c文件中CVMgcUnsafeExecuteJavaMethod() 函数)。解释器围绕switch声明循环,直到没有bytecode需要执行。对那些频繁执行的方法(我们一般叫它们热点),JIT会编译这些方法到本地机器代码。编译后的方法会在做bytecode解释的一个地方被执行。

       这儿有许多的方式来测试方法的热烈。CLDC VM使用一个基于取样机制的计时器。象写的这样,CVM使用采样祈祷(invocation)计数在整个解释期间。上面到达了一些开始的热点,方法得到编译。这个问题现在变成了怎么样从解释器bytecode到执行编译后的方法。为了理解这个(所有其他java代码执行的要点),我们需要看看在运行时堆里发生了什么,当java代码执行的时候。

运行时堆

       象前面说的,CVM里的每一个java线程有2个堆:一个本地堆和一个java堆。Java堆一般作为解释器堆。CVM里的每一个线程是一个标示作为CVMExecEnv记录的一个指针。我们通常把这叫做ee,通过ee,我们总能象下面这样找到java堆:

           CVMStack *currentStack = &ee->interpreterStack;

Java

       Java堆是CVMStack的类型(可用看stacks.hstacks.h)。这个堆被组织成一个堆块链表的样子。当堆在CVMinitStack()里被初始化时,它会分配一个堆块。如果一个堆里需要更多的内存,那么附加的块会被分配。因此java堆是可增长的。理论上,堆也能够被缩小,但现在的代码不支持这样做。

       方法活动记录存储在结构(frame)中。基本的类结构是CVMFrame(看stacks.h)。这儿也有CVMFreeListFrame(看stacks.h),CVMJavaFrameCVMTransitionFrameCVMCompiledFrame(看interpreter.h)。所有的这些结构都CVMFrame的多态。注意:尽管CVM是用C写的,它使用了一些对象导向的范例在它的设计中。一些数据结构是多态在制造它的感觉的地方。

       CVMFrame来自frames链表并能跨过堆块。这些链表的头(bottom-most frame in the stack)总是已知的因为它总是堆的第一块。链表的最后一个结构(top most frame in stack)是CVMStack里面currentFrame指针

CVMJavaFrame

       CVMJavaFrame是一个用在bytecode解释器方法里的结构。在调用方法前,VM会把CVMJavaFrame推入堆。结构会根据信息被初始化,信息通过调用CVMMethodBlock *来得到。方法元数据存储在被叫做CVMMethodBlock的数据结构中(通常叫mbMB)。MB的地址被用来作为方法的唯一标示。因此,这就是什么存储在结构中了。结构也包含程序计数器值(program counter = PC)。在这个例子中,PC是一个指向下一个要执行的bytecode的指针(作为方法调用的返回)。当前PC不总是最新的结构。代替它的是保持在解释器循环的本地状态。

       Frame的结构看起来象下面:

                          |-----------------|
      start of frame ---> | locals ...      |
                          |-----------------|
                          | frame info      |
                          | (CVMJavaFrame)  |
                          |-----------------|
       top of stack ----> | operand stack   |
                          | ...             |
                          |-----------------|

       Locals区域掌握java locals(VM spec中定义),操作数堆区域是VM推入推出操作数的地方,这些操作数用来推算opcode,或者是被调用方法的外部(outgoing)参数,或者是刚刚被调用方法的返回值。

       VM speclocals的数量和最大操作数堆容量在任何给定的bytecode方法的时间前是已知的。因此,我们知道如果堆块有足够的房间剩余,在我们把frame推入前。如果没有,那么一个新的堆块将被分配,frame将被推入下一个块实例。

       自从外部(outgoing)参数(对于下一个被调用的方法)存储在操作数堆,操作数堆的一部分成为locals区域的开始,对于下一个frame来说,象下面:

                          |-----------------|
      start of frame ---> | locals ...      |
                          |-----------------|
                          | Method 1        |
                          | frame info      |
                          |-----------------|
                          | operand stack   |
                          |                 |-----------------|
 start of next frame ---> |   outgoing args = incoming locals |
                          |                 |                 |
                          |-----------------|                 |
                                            |-----------------|
                                            | Method 2        |
                                            | frame info      |
                                            |-----------------|
        top of stack ---------------------> | operand stack   |
                                            |                 |
                                            |-----------------| 

这是VM spec说的是一致的,传入的参数开始于0索引的局部区域frame

注意:在CVM中,局部和操作数堆是字空间槽(slot)。在32-bit系统中,这意味着32-bit的内存。堆指针的增长是字增长。这些字能够包含java私有类型(64bit值会占2个槽),或者对象指针。

CVMFreeListFrame

       一个使用freelist frame的是JNI方法的frameFrame的结构如下:

                          |--------------------|
      start of frame ---> | frame info         |
                          | (CVMFreeListFrame) |
                          |--------------------|
                          | operand stack      |
       top of stack ----> | ...                |
                          |--------------------| 
        一个不同是这儿没有引入的lacals或者任何种类的localsJNI方法,传入的参数存储在本地方法的堆栈结构中。这些参数是调用结构(caller frame)操作数堆栈中外部参数的一个拷贝。这个拷贝是汇编调用本地粘和的一部份(在这儿查看invokeNative_arm.S中的CVMjniInvokeNative)。
        另一个不同是操作数堆栈区域只是用来存储对象指针。其他操作数存储在CPU寄存器或本地堆栈(依靠C编译器编译的本地方法)。在JNI中,当你使用NewLocalRef分配局部引用,存储对象指针的堆栈分配一个freelist结构。当你使用DeleteLocalRef释放引用,堆栈slot从一个叫freelist的链表中得到chained。列表的头是CVMFreeListFrame中的记录。JNI方法的MB指针的一个拷贝也存储在这儿。当你分配一个局部引用,我们首先检查freelist的可用引用,如果有一个可用,引用被从列表里移动并返回。如果没有可用,我们碰(bump)顶部的堆栈指针,从操作数堆栈的顶部分配。
        注意,不象Java bytecode方法,我们不知道操作数能分配的最大数。幸运的我也不需要知道。不象Java framefreelist结构能够横跨堆栈块。如果我们在当前块的外部运行,我们简单的添加从其他新的块分配的块到堆栈。
        Freelist其他用法是执行GC根堆栈。GC根堆栈执行使用一个CVMStack和在它里面的一个freelist。因此GC根堆栈是真正假象的对象引用列表,几个GC根能够分配和释放(当你调用JNINewGlobalRoot()DeleteGlobalRoot()方法),freelist frame是很好的执行。

CVMTransitionFrame

       传输结构机制(transition frame mechanism)是一个聪明的诀窍为了得到解释器调用方法,为我们不需要写一大堆代码。它的工作是连同一个特别的指向一个需要调用的目标方法的常量池入口模拟一个byte code方法。常量池入口不少真正的常量,但它可在解释器循环中使用。解释器设置常量池入口指向目标方法的MB。接着,它要求调用4个叫transition假方法(看executejava_standard.c中的这些方法CVMinvokeStaticTransitionCode, CVMinvokeVirtualTransitionCode,CVMinvokeNonVirtualTransitionCode, CVMinvokeInterfaceTransitionCode)中的一个。这些传输方法的选择依靠我们想要调用的类型。

       这个机制用来调用静态初始化方法,另一个为了一步一步的进入java代码里的第一个方法。

CVMCompiledFrame

       最后,我们解释编译结构,如下:

                          |--------------------|
      start of frame ---> | locals ...         |
                          |--------------------|
                          | frame info         |
                          | (CVMCompiledFrame) |
                          |--------------------|
                          | spill/temp area    |
                          |--------------------|
                          | ...                |
       top of stack ----> | operand stack      |
                          | ...                |
                          |--------------------| 

    Java结构,CVMCompiledFrame包含了一个MB指针和一个PC。在这里PC是一个指向编译后代码(指示下一个执行)的指针(返回PC类型)。当VM要调用方法时,它首先检查方法是否编译了,是否是本地代码。对本地代码来说,freelist frame被调用本地粘合汇编代码推入在方法被调用前。“未编译”或bytecode方法有一个java结构推入,在解释器循环中连续执行。如果方法已编译,一个编译后结构会被推入,VM会直接跳到指向编译后方法的指针处继续执行。

On-Stack交换

如果方法已经在循环中被解释很长的时间,我们决定编译它。。。当我们已经解释了一半的方法,那我们怎么样继续执行编译后的方法呢?我们需要的一个特性叫做On-Stack ReplacementOSR)。OSR允许我们替换堆里面的java frame用一个相同的编译后frame

       注意,编译后frame的形态和java frame非常相似。唯一的不同是附加的spill/temp区域。这个区域在方法编译后是已知固定大小的(在framepush前)。这儿的确有其他的不同。一个编译后frame能够有更多的局部比java frame副本当方法内联期间。同样,操作数堆区域的大小也不同。在设计上,CVM JIT保持同样的locals映射对编译后方法作为相应的bytecode。那些从内联方法加入的locals被作为更高的索引被添加。这意味着它能更容易的从java frame到编译后frame。作为编译后frame新特性信息,我们能计算从java frame 信息中不需要的成就

       离开spill区域和操作数堆,一个我们制造的观察是因为自然生成的bytecode从编辑所有的java语言。操作数堆会趋向为空,当循环开始的时候。这在今天的javac编译器情况下有99%是真的(这是一个疯狂的猜测但极可能是对的)Hot循环在我们想要OSR发生的地方。这意味着在操作数堆上没有什么被映射当我们开始循环的时候,我们能够取得优势来做OSR

       作为spill区域,CVM JIT不能产生溢出内容在循环的开始。因此,唯一需要做的一件事是为它在新的frame中储备一些空间。因为这些,我们能替换hot loops,用同样编译后的替换部分解释器。

       注意:CVM只支持java frameOSR连同他们对等的编译后frame,而不是其他方向。其它方向中的OSR是值得注意的更多的困难和更多的招数导致更多的开销而不适合JavaME系统。这会是一个区域,那些团体能够选择调查在未来,如果它希望。这儿有一些有趣的高级的事能够和OSR相反的来做,如果我们从来没有接触它,我为在其他时候离开。

下一个是什么?

      我们已经介绍了java stack结构和CVM。明天,我会简要的谈论关于本地stack frame(那些嵌入式程序员应该很熟悉它)和更多的有趣的。我会谈论他们之间的相互影响,因此,请看这个讨论的第2部分。

祝有美好的一天!!

2007年08月16日

 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/the_big_picture.html

 

         亲自的,当你接触一个新系统,第一件事是你想要搞清楚每一个东西是怎么结合在一起的。如果你像我一样是个虚拟思考者,最好的一条路就是画一个图表来说明你觉得重要的东西以及他们之间的联系。嵌入式系统的一个例子,以我的经验,知道内存里有什么在哪儿,系统资源是怎样使用的也同样重要,因此我画了一个数据结构的图表,下面:

CVM的世界参考物?

下面是怎么来读这张图

根数据结构

       CVM的一个设计标准是可重新启动,甚至当你在没有进程的OS上运行它。没有进程需求的可重启性,我们能够释放所有分配的内存。为了让生活更容易(它总是一个很好的实践),我们必须确保所有的数据从单一数据结构书的根上是可获得的。这个根数据结构是CVMglobals,你能在上面地图的左边看到。你会在globals.hglobals.c里找到CVMglobals的定义(也可以在这个文件里找到CVMGlobalState)。看下CVMglobals,你会发现它是一个系统全局数据结构的集合。保证全局在一个地方可以让它更容易恢复已知的初始值。例如:使用memsetting把所有的值设为0(在外面清理了所有的数据后)。

垃圾回收和Java堆栈:

       从全局,你可以找到一个内嵌的结构,它把握GC的配置和管理信息(CVMglobals.gc)。从这些,你最终可以得到Java heap。

       CVM有可插件的GC体系。插件是编译时的可插件性,不是运行时。它允许在CVM里根据实验来试验GC。当前,唯一一个有品质保证的CVM的GC是世代的(generational)GC(在这儿这儿可以看到GC的细节执行文件)。

       所有的java对象,也就是所有从java.lang.Object扩展的对象,都从java heap上分配。只有一个例外就是ROMized Java objects。它们存在于全局数据。javaheap自己从C heap上分配。所有其它数据结构都从全局数据(i.e. .bss, .data, or their equivalents)或从C heap分配。

JIT和编译后代码

       CVMglobals为JIT(CVMglobals.jit)掌握配置和管理记录。通过树,你最后会找到JIT代码缓冲。这个代码缓存当前是固定大小的(通过运行时可配置)它在VM启动时分配。一旦它被分配,它的大小不能被改变。

       当java方法被JIT编译,编译器生产的比特(通常作为编译后方法提及)会存在代码缓存中。编译后方法的原数据(meta-data)(由JIT生成)也会存储在代码缓存中。因此,代码缓存的大小会规定,间接的,有多少方法能被编译。

Java对象和类

       当类文件装载到内存,内容主要被解析和组织到一个最佳的结构,它从C heap里分配。这个结构叫CVMClassBlock,它掌握所有类的元数据。原数据包括常量池,类属性,域和方法信息,bytecode等等。对每一个CVMClassBlock,有一个从java heap分配的java.lang.Class的实例。一旦一个类已经被装载,它们总是作为一对存在。类块(classblock)有一个参考对一个类,反之亦然。当一个类unload时,它们会一起被释放。

       CVM里的每一个java对象有一个2个字的头。第一个字包含了一个指针指向类块。无论如何,这个头对java代码不可见,它只对VM里的C方面可见。注意:自从java.lang.Class扩展自java.lang.Object后,类实例也有2个字的头

       查找关键文件在objects.h and classes.h。 看

Java线程

       要执行任何东西,VM必须有线程。每个java线程由CVMExecEnv表现(通常缩写成ee)。在VM,本质上ee是 线程的标示符。所有线程操作请求作为当前执行的线程的ee的参数。看interpreter.h 和 interpreter.c 

       这儿有一个一对一的映射关系在ee和java.lang.Thread实例之间。一旦线程被初始化,它们2个就作为一对存在。

       这儿有一个一对一的映射关系在ee和JNIEnv之间。JNIEnv是一个嵌入的,作为ee的一个域。ee和JNIEnv之间的映射地址的基本需求只是偏移调整。

       所有ee被装载在一个链表里。这个链表的头是CVMglobals.threadList。主线程的ee被做为嵌入域在CVMglobals被分配。

系统互斥

       VM线程列表的操作需要被同步。在VM里的其他子系统和资源都一样。同步一般都由CVMSysMutex(看sync.hsync.c)。在VM启动时有几个系统互斥量(sysMutexes)被分配。这些互斥量只对VMC代码可见。只能被C代码使用。

       每个互斥量都有明确的目的(CVMglobals.threadLock用来同步线程),它是有序的。为了防止死锁,系统互斥量只能在增加序号时被锁住。当CVM使用断言建立时,升序可以被断言。

Java执行堆

       一个执行的线程必须有一个执行堆。在CVM里,每一个Java线程有2个物理堆:一个本地堆,一个java堆。本地堆由系统分配,用于C代码执行。它掌握本地代码的活动记录(堆帧 stack frames),VM代码包括解释器循环功能。它掌握所有JIT编译后代码的活动帧。

    Java堆(也叫解释器堆)用来保存所有java方法的活动记录。每个java方法一执行,一个帧会推入堆中。堆和帧数据结构定义在stacks.hstacks.c中。

    如果你在执行java方法时dump一个本地堆的跟踪,你会看到C代码的堆帧(stack frames)和解释器循环。如果你dump一个java堆,你只能看到java代码的堆帧当它们被调用时。如果你有一个本地方法在执行链(invocation chain),你可以看到本地堆和java堆的堆帧。这是因为本地方法是C功能和java方法的和。

GC根和根堆

GC阶段,CVM被称为一个精确的VM。这意味着在GC时间,我们能够确切的知道所有的对象指针在系统的哪个地方。这和需要你猜测某个内存片包含对象指针和一些类似对象指针的随即数据的老式GC系统有鲜明的对比。

      VM里所有能获得的对象能够通过跟踪被叫做垃圾回收根树的对象参考树来找到。这个树从一个根参考开始。这些根参考本质上是全局的。用来存储被称为根堆(root stacks)的数据结构。有一个例子是CVMglobals.globalRoots。准确的说,这些数据结构不需要成为堆。它们被作为链表来使用。无论如何,我们的java堆数据结构有道具来实现GC根堆的需要,不要请求我们写附加的代码(为了代码效率),因此我们只使用堆。

       如果一个对象不能通过跟踪根树来找到,那么对象是不可到的,它可以被GC再生。

       注意在穿越树中,任何的点,一个节点都可能是新的子树的根。因此,term root或者GC根有时被用来指向一个对象指针/参考,它总能通过根查找来找到。GC根能在根堆里找到,在线成执行堆,在对象和类域里。

终了

      给了你们上面的主意足够让你们了解CVM里最主要的数据结构。注意:我告诉你们的大部分事给了你们一个很好的概念模型。实践上,这儿有一系列的原因来导致异常。某些时候,这些异常会打破规则。另外一些时候,他们看起来象是扩展了规则。为了保持事情简单,我忽略了它们。当我在谈到每个子系统或特殊的数据结构的时候我会详细讨论它们。

       在上面,我忽略了一些有趣的细节,比如为什么从C heap 分配数据结构相对于java heap。几天或几周后,我会放大CVM的子系统或数据结构,详细的讨论它们。这包括机械的细节作为设计体系。

祝有美好的一天!!