<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>隔叶黄莺 Unmi Blog &#187; JVM</title>
	<atom:link href="http://unmi.cc/category/javajee/jvm/feed" rel="self" type="application/rss+xml" />
	<link>http://unmi.cc</link>
	<description></description>
	<lastBuildDate>Wed, 22 Feb 2012 14:20:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>用 jreloader 动态重新加载改变的类而不用重启 JVM</title>
		<link>http://unmi.cc/jreloader-reload-class</link>
		<comments>http://unmi.cc/jreloader-reload-class#comments</comments>
		<pubDate>Fri, 28 Jan 2011 12:02:27 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[Java/JEE]]></category>
		<category><![CDATA[JVM]]></category>
		<category><![CDATA[jreloader]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Tomcat]]></category>

		<guid isPermaLink="false">http://unmi.cc/?p=3111</guid>
		<description><![CDATA[在 Tomcat 中可以配置 reloadable="true" 做到类改变后，Tomcat 重新加载。其实这个过程大约也是当 Tomcat 发现有改变的类会重新启动一个新的应用程序重新加载所有的类来服务于新的请求，只是不需要你手动的去执行 shutdown.sh(.bat)，再 startup.sh(.bat)。这种方式对于古老的 jsp 程序完全能从容以对，因为 web.xml 里几乎没什么随应用一起启动且耗时长代码；但当下是框架横行，web.xml 中随应用一起启动的程度可谓是争先恐后的，所以仅仅依赖 reloadable="true" 是满足不了需求的。每改一个类(无论是改动了方法体中的代码还是变动了类的结构，准确的说是动了 WEB-INF/classes 目录中的任何文件) 你都可能就会在 Jan 28, 2011 7:19:42 PM org.apache.catalina.core.ApplicationContext log INFO: Initializing Spring root WebApplicationContext 这一步上等上半天，况且对于 reloadable="true" 对于类结构的改动是无动为力的，像实现了不同的接口，继承了不同的类，或者增删了方法或属性的时候，Tomcat 必须是 shutdown，然而再 startup 的。 这样的频繁重启对于调试是一种煎熬，所以希望能找到一个工具，能在类改动的时候不需要重新启动当前应用，当然不希望重启 Tomcat 了。能实现此功能的工具有 JavaRebel 和 jreloader，其中前者是收费的，后者是开源的，不过后者实际上也不错。 这里介绍下后者在 Eclipse WTP  Tomcat 环境中怎么配置使用。 当前版本是 jreloader-0.4.zip，其中有 jreloader.jar 和 jreloader-src.zip，再就是非常简单且足够的 [...]]]></description>
		<wfw:commentRss>http://unmi.cc/jreloader-reload-class/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Java 的方法签名与字段类型表示-[Ljava.lang.String;</title>
		<link>http://unmi.cc/java-signatures-data-types</link>
		<comments>http://unmi.cc/java-signatures-data-types#comments</comments>
		<pubDate>Mon, 10 Jan 2011 17:19:39 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/?p=3040</guid>
		<description><![CDATA[我们什么时候会接触到 Java 的方法签名呢？在进行 JNI 调用时，还有在看方法重载时。重载的方法是有不同的方法签名的，而是不区分返回值，而实际方法签名还揉入了返回值类型的，还有就是 javap -s 查看方法签名时，如 javap -s java.util.Date。 看来方法签名与我们实际工作的关系还真的不大。倒是有次遇着了，事出于 Struts2 应用中提交表单时报出了下面的错误： 00:43:59.716 [http-8080-4] WARN  com.opensymphony.xwork2.ognl.OgnlValueStack - Error setting expression 'version' with value '[Ljava.lang.String;@e18a9a' ognl.MethodFailedException: Method "setVersion" failed for object cc.unmi.model.Post@ed0cd7  at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1285) ~[ognl-3.0.jar:na]  at ognl.OgnlRuntime.setMethodValue(OgnlRuntime.java:1474) ~[ognl-3.0.jar:na]  at ognl.ObjectPropertyAccessor.setPossibleProperty(ObjectPropertyAccessor.java:85) ~[ognl-3.0.jar:na]  at ognl.ObjectPropertyAccessor.setProperty(ObjectPropertyAccessor.java:162) ~[ognl-3.0.jar:na]  at com.opensymphony.xwork2.ognl.accessor.ObjectAccessor.setProperty(ObjectAccessor.java:27) ~[xwork-core-2.2.1.jar:2.2.1]  at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:2245) ~[ognl-3.0.jar:na]  at com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor.setProperty(CompoundRootAccessor.java:77) ~[xwork-core-2.2.1.jar:2.2.1]  at [...]]]></description>
		<wfw:commentRss>http://unmi.cc/java-signatures-data-types/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>四、深入下package,import:(摘)</title>
		<link>http://unmi.cc/inside-package-import-4</link>
		<comments>http://unmi.cc/inside-package-import-4#comments</comments>
		<pubDate>Fri, 10 Apr 2009 16:19:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/%e5%9b%9b%e3%80%81%e6%b7%b1%e5%85%a5%e4%b8%8bpackageimport%e6%91%98</guid>
		<description><![CDATA[注：因package,import涉及较多内容，另开一个帖子了，但为了保证此贴内容与标题相符，在此也把写上了该部分内容（措辞有整理）   深入下package,import:     凡是和java设计相关的工具，都会用到package与import，到底这两个东东是做什么的，如何用，它们的内部机理又是如何呢，今仅就个人的理解谈谈看法，里面一些错漏，疑点也请朋友们指出： 一， package,import引入原因： package:     我们都熟悉超市，超市虽然庞大，东西繁多，但管理的井井有条，很容易找到某样东东，；之所以能如此，一个很重要的原因就是采用了分类放置，这样既方便了管理，又方便了寻找     Package也是一个分类放置东东的区域，不过它放的不是商品而是java中的类。Java中有各种各样的类， 内容丰富，繁多，为了更好的管理，识别，就为每一类型的类建立一个区域，这个区域就是包 import:     类放入了包中，在运行时如何才能定位到类呢？，我们知道，类分三种，“系统类”，“扩展类”，“用户类”；前两种的路径由jvm指定； 而用户类是通过 “–classpath”, “classpath”和缺省路径“.”与import配合来查找的，查找顺序如下：     1. -classpath(命令行模式下使用);     2. classpath(在环境变量中设计，当有 –classpath时该路径信息不起作用)     3. 缺省路径”.” 当前目录(当前两步都没有时，才会使用缺省路径)     朋友们不知是否想过这样的问题：           既然“系统类”，“扩展类”，“用户类”java都有机制对应到它们的路径，那为什么还要引入import呢？ 这似乎是个有趣的话题       我们知道，java程序在运行时，除了一些预先载入的类可以通过系统内定的路径（写死）所有的类必须要“精确”（请注意喔，是精确）定义位置，而无论是jvm还是classpath它们对于运行时加载的类的路径指明不具体，很笼统，大致如下：         [...]]]></description>
		<wfw:commentRss>http://unmi.cc/inside-package-import-4/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>三、我对java中类路径的理解(摘)</title>
		<link>http://unmi.cc/understand-java-classpath</link>
		<comments>http://unmi.cc/understand-java-classpath#comments</comments>
		<pubDate>Fri, 10 Apr 2009 16:18:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[classpath]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/%e4%b8%89%e3%80%81%e6%88%91%e5%af%b9java%e4%b8%ad%e7%b1%bb%e8%b7%af%e5%be%84%e7%9a%84%e7%90%86%e8%a7%a3%e6%91%98</guid>
		<description><![CDATA[Java中的类路径分“编译后的存放路径” 和 “运行时的查找路径”，下面分别谈谈 1. java编译后的类存放路径， 分两种：“源文件被直接编译”和“源文件被间接编译”         1-1源文件直接编译           什么是源文件直接编译：即通过javac直接编译源文件 建立d:\my目录，在其目录下新建一个文件，如下： Public class HelloWorld{     Public static void main(String[] args){         System.out.println(“HelloWorld”);     } } 在命令行输入： javac HelloWorld.java 这时在d:\my这个目录下就产生了一个类文件HelloWorld.class 在命令行输入： java HelloWorld HelloWorld 正常输出 改变一： 把原文件中的输出内容改为”changeHelloWorld” 重新编译，运行，可以看到在控制台输出了 changeHelloWorld 改变二: 恢复一的改变，并删除之前生成的类文件， 在源文件中的头部加入 Package com.test； [...]]]></description>
		<wfw:commentRss>http://unmi.cc/understand-java-classpath/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>二、我对java中类装载的理解(摘)</title>
		<link>http://unmi.cc/understand-java-classloader</link>
		<comments>http://unmi.cc/understand-java-classloader#comments</comments>
		<pubDate>Fri, 10 Apr 2009 16:13:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[ClassLoader]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/%e4%ba%8c%e3%80%81%e6%88%91%e5%af%b9java%e4%b8%ad%e7%b1%bb%e8%a3%85%e8%bd%bd%e7%9a%84%e7%90%86%e8%a7%a3%e6%91%98</guid>
		<description><![CDATA[1.Java中的所有类，必须被装载到jvm中才能运行，这个装载工作是由jvm中的类装载器完成的， 类装载器所做的工作实质是把类文件从硬盘读取到内存中 2.java中的类大致分为三种：     1.系统类     2.扩展类     3.由程序员自定义的类 3.类装载方式，有两种     1.隐式装载， 程序在运行过程中当碰到通过new 等方式生成对象时，隐式调用类装载器加载对应的类到jvm中，     2.显式装载， 通过class.forname()等方法，显式加载需要的类   隐式加载与显式加载的区别：     两者本质是一样?，     ？ 4.类加载的动态性体现     一个应用程序总是由n多个类组成，Java程序启动时，并不是一次把所有的类全部加载后再 运行，它总是先把保证程序运行的基础类一次性加载到jvm中，其它类等到jvm用到的时候再加载，这样的好处是节省了内存的开销，因为java最早就是为嵌入式系统而设计的，内存宝贵，这是一种可以理解的机制，而用到时再加载这也是java动态性的一种体现 5．java类装载器     Java中的类装载器实质上也是类，功能是把类载入jvm中，值得注意的是jvm的类装载器并不是一个，而是三个，层次结构如下：       Bootstrap Loader  - 负责加载系统类             &#124;       [...]]]></description>
		<wfw:commentRss>http://unmi.cc/understand-java-classloader/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一、我对java中编码的理解(摘)</title>
		<link>http://unmi.cc/understand-java-encoding</link>
		<comments>http://unmi.cc/understand-java-encoding#comments</comments>
		<pubDate>Fri, 10 Apr 2009 16:12:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[encoding]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/%e4%b8%80%e3%80%81%e6%88%91%e5%af%b9java%e4%b8%ad%e7%bc%96%e7%a0%81%e7%9a%84%e7%90%86%e8%a7%a3%e6%91%98</guid>
		<description><![CDATA[1. 编码的产生     对电脑而言，只认识0，1； 而现实世界是由各种符合组成，要想让计算机解释现实世界，就必须建立一套现实世界中的符号 和 计算机能处理的符号之间的对应关系，这个对应关系就是编码 2. 在一个编辑器中，当我们在键盘上敲入一个字符时，在该编辑器上就会显示对应的字符，这个过程用计算机执行步骤来解释大致如下：     输入字符 –&#62; 编辑器根据设定的编码格式把字符编成01格式 -&#62; 编辑器再按编码规则对01解码–&#62; 显示字符 3.几种常见的编码格式 1. ASCII码：      计算机中最早的一套编码格式，采用7位二进制表示一个常见的字符，我们知道，计算机是按照字节来处理数据的，一个字节8位，因此用一个字节就可以表示一个ASCII字符，且还有一个位空位，规定最高位不用，常见的把最高位设定为0。 7位二进制最多可以表示128个字符（2的7次方），ASCII码只能表示常见的英文字符，数字，和少量的符号（没办法，谁让计算机是人家老美先发明的啊，优先考虑本土语言，理解理解） 注： 由于ASCII最早定义，使用广泛，使得之后出现的新的”字符“(不是汉字喔)编码都尽量和它兼容  2. iso-8859-1：     尽管ASCII应用广泛，但是由于它定义的字符太少，即使对于同是使用字母语言的国家也不够用，更别说我们汉字啦，西欧许多国家使用拉丁语言，其中的很多字符ASCII编码都不认识喔，这当然会让它们不爽啦，总不能因为这个问题让那些国家的人不使用电脑吧， 于是ISO/IEC就推出了另外的一套编码标准ISO-8859-1. 这套标准完全和ASCII兼容，它使用8位二进制表示一个字符 —--- 刚好一个字节，其中最高位是0时的解释和ASCII一样（这样不就完全兼容啦，兼容很好理解吧），但最高位是1时则用于定义其它字符，这样就在保证和ASCII兼容的同时又扩展了ASCII，可以多表示字符啦 3. GBK编码     光有字母语言国家的编码就可以么？， 可以啊，好好学习英语啊， 要不你看不懂啊，不想学？，那就不玩啊，呵呵，当然不会啦，对于中国，韩国，日本等这些国家，推出了一种新的编码GBK码， 在编码上GBK采用单双字节混合的方式，它也兼容ASCII喔，具体GBK怎么个编码，你查看资料啦， 这里重点关注的是编码的演化,提供的是思路哈 4. Unicode     Unicode是为了打破这种编码的各自为政，带有强烈地域性的标示而推出的一种编码格式，目的是要达到世界的大同，大同好啊，方便交流啊，就是晚了点，计算机一出现就出来多好，就没了现在让程序员头疼的编码转来转去的麻烦了，恩，看来有界限的人心是会带来麻烦的，好了，啰嗦了这么多，才算真正引入正题，为什么会出现乱码，如何解决乱码     4. 揭示web中乱码的病因   [...]]]></description>
		<wfw:commentRss>http://unmi.cc/understand-java-encoding/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>JVM 对 Java 异常的处理原理（try.catch 子句）</title>
		<link>http://unmi.cc/jvm-java-handle-try-catch</link>
		<comments>http://unmi.cc/jvm-java-handle-try-catch#comments</comments>
		<pubDate>Tue, 07 Apr 2009 14:38:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[Exception]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/jvm-%e5%af%b9-java-%e5%bc%82%e5%b8%b8%e7%9a%84%e5%a4%84%e7%90%86%e5%8e%9f%e7%90%86%ef%bc%88try-catch-%e5%ad%90%e5%8f%a5%ef%bc%89</guid>
		<description><![CDATA[最初我们用 Java 写 JSP 的时候，几乎可以不触及异常，因为 Servlet 容器会把 API 抛出的异常包装成 ServletException 丢给容器去处理。再后来应用分层，代码中要处理的异常便多了，一般会转换成自定义的业务异常类，用 try-catch-throw customerException-finally。再到如今各种框架日臻成熟，代码中显式的异常处理又渐渐少了些，借助于 AOP 横行，异常对业务的影响描述被移入到了配置文件中了，例如，事物处理、权限的控制等。 这颇有些像手机的发展，当通信技术不甚发达的时候，手里抓的是砖头，信号是模拟的。后来慢慢瘦身成两三根手指大小，甚至是就一支笔似的，可如今信息量大了，屏幕要大，再配上 QWERT 键盘，机身自然就肥硕了。 当然与手机的个头变迁略有不同的是，任凭你怎么对待 Java 中异常，切入 AOP 也好，在 JVM 中处理异常的内在机制始终未变。 说到 Java 异常，无外乎就是 try、catch、finally、throw、throws 这么几个关键字，这些个的用法是没必要在这里讲了。我们这里主要关键一下 catch 和 finally 是如何在编译后的 class 字节码中的。 异常的抛出与捕获，Catch 子句的表现，来看看一段 Java 代码及生成的相应字节码指令。 package com.unmi; import java.io.UnsupportedEncodingException; public class AboutCatch { public static void main(String[] args){ try { transfer("JVM [...]]]></description>
		<wfw:commentRss>http://unmi.cc/jvm-java-handle-try-catch/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>有关于 JVM 的垃圾收集(三)</title>
		<link>http://unmi.cc/about-jvm-gc-3</link>
		<comments>http://unmi.cc/about-jvm-gc-3#comments</comments>
		<pubDate>Wed, 01 Apr 2009 05:27:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[gc]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/%e6%9c%89%e5%85%b3%e4%ba%8e-jvm-%e7%9a%84%e5%9e%83%e5%9c%be%e6%94%b6%e9%9b%86%e4%b8%89</guid>
		<description><![CDATA[对象可触及时的生命周期 在 JVM 1.2 之前，堆中的对象分为三种状态，分别是： 1. 可触及的 -- 从根节点开始可追踪到 2. 可复活的 -- 从根节点开始追踪不到，但有可能被终结方法触及并复活。不仅仅是那些声明了 finalize() 方法的对象，而是所有的对象都要经过可复活状态 3. 不可触及的 -- 以上两种可能性都不存在，可以真正回收它们所占据的内存了 版本 1.2 中，可触及按强弱进一步细分为： 1. 强可触及 -- 即原来的可触及，从根节点开始的任何直接引用，如一个局部变量或任何从强可触及对象的实例引用的对象 2. 软可触及 -- 表现为 SoftReference 所引用的对象 3. 弱可触及 -- 表现为 WeakReference 所引用的对象 4. 影子可触及 -- 表现为 PhantomReference 所引用的对象 SoftReference、WeakReference、PhantomReference 都是 java.lang.ref.Reference 类的子类。强引用与这三种弱引用之间最基本的差别是，强引用禁止引用目标被垃圾收集，而那三种引用不禁止。 要创建某一对象的软引用、弱引用或是影子引用，只需简单的包装一下。例如，创建一个 cow 对象的软用就写成： SoftReference softCow = new [...]]]></description>
		<wfw:commentRss>http://unmi.cc/about-jvm-gc-3/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>有关于 JVM 的垃圾收集(二)</title>
		<link>http://unmi.cc/about-jvm-gc</link>
		<comments>http://unmi.cc/about-jvm-gc#comments</comments>
		<pubDate>Tue, 16 Dec 2008 03:51:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[gc]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/%e6%9c%89%e5%85%b3%e4%ba%8e-jvm-%e7%9a%84%e5%9e%83%e5%9c%be%e6%94%b6%e9%9b%86%e4%ba%8c</guid>
		<description><![CDATA[自适应收集器 在第一篇：有关于 JVM 的垃圾收集(一)  中谈到过几种垃圾收集的算法，然而我们的 JVM 启动之后并不要求彻头彻尾的死板的使用一种垃圾收集算法，固定的算法参数。因为某种情况下某些垃圾收集算法工作得更好，而别外一些收集算法在另外的情况下工作得更好，所以自适应的垃圾收集技术应运而生。自适应算法监视堆中的情形，并且对应的调整为合适的垃圾收集技术。或能是换一种垃圾收集算法，或者是调整当前算法参数，或者把堆划分为子堆，同时在不同的子堆中使用不同的算法。 简述火车算法 垃圾收集一般都会停止整个程序的运行来查找和收集垃圾对象，它们可能在程序执行的任意时刻暂停，并且暂停的时间也无法确定。垃圾收集也可能使得程序对事件响应迟钝，无法满足实时系统的要求。如果一种垃圾收集算法可能导致用户可察觉的到的停顿或者使得程序无法适合实时系统的要求，这种算法被称作破坏性。垃圾收集算法的还有一个基本目标是使本质上的破坏性尽可能少，如果可能的话，尽可能消除这种破坏性。 达到(或试图达到) 非破坏性垃圾收集的方法是使用渐进式收集算法。渐进式收集器就是不试图一次性发现并回收所有不可触及的对象，而是每次发现并回收一部分。因为每次只有堆的一部分执行垃圾收集，因此理论上说每次收集会持续更短的时间。保证这个最短时间接近某一个时长，就可以让 Java 虚拟机适合实时环境，也就可以消除用户可察觉的垃圾收集停顿，这可称之为限时渐近时垃圾收集。 渐进式收集器通常是分代收集的，大部分调用中，都是收集堆的一部分。大部分对象都是短命的，利用这一点，分代收集器在年幼子堆中比在年长子堆中更活跃。因为除了最高寿的子堆(成熟对象空间) 外，每个子堆中都可以给定一个最大尺寸，分代收集器大体上可以保证在一个最大时间内渐进地收集所有对象(最高寿的除外)。成熟对象空间无法给定最大尺寸，因为其中的对象不适合时没个去处。 于是针对成熟对象空间提供限定时间的渐时收集，Richard Hudson 和 Eliot Moss 提出了火车算法，目前正用于 Sun 公司的 Hotspot 虚拟机中。该算法详细说明了分代收集的垃圾收集器的成熟对象空间的组织。大体有些车厢、火车、火车站的概念，对于该算法的此处不作进一步说明了。 finalize() 方法 一个 Java 对象可以拥用终结方法：这个方法在垃圾收集器释放对象之前必须运行。但这么一个终结方法的引入并不明智，会使得 JVM 的垃圾收集的工作变得更得杂，所以别用它。 因为，存在终结方法时，垃圾收集器必须在每次在收集时执行一些额外的步骤。首先第一遍扫描时，垃圾收集器检测出不再被引用的对象，然后看那些对象上是否声明了终结方法，有则执行。当执行了所有的终结方法后，垃圾收集器必须再次从根节点或是需要执行终结的对象开始检测不再被引用的对象，这称作第二遍扫描。这个步骤是必要的，因为终结方法可能“复活”了第一遍扫描标记的对象。最后，垃圾收集器才能释放那些在第一遍和第二遍扫描中发现的都没有被引用的对象。 如果第一遍扫描标记不再引用的对象的终结方法运行过了，而后这个对象被自己或其他对象的终结方法复活了，稍后再次被收集时，执行过的终结方法就不能再执行了。同时终结方法何时被执行也是无法预测的。]]></description>
		<wfw:commentRss>http://unmi.cc/about-jvm-gc/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>简单例子演示如何进行类的热加载(Hot Deployment)</title>
		<link>http://unmi.cc/simple-java-hot-deployment</link>
		<comments>http://unmi.cc/simple-java-hot-deployment#comments</comments>
		<pubDate>Tue, 21 Oct 2008 16:38:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[Hot]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/%e7%ae%80%e5%8d%95%e4%be%8b%e5%ad%90%e6%bc%94%e7%a4%ba%e5%a6%82%e4%bd%95%e8%bf%9b%e8%a1%8c%e7%b1%bb%e7%9a%84%e7%83%ad%e5%8a%a0%e8%bd%bdhot-deployment</guid>
		<description><![CDATA[应用服务器一般都支持热部署(Hot Deployment)，更新代码时把新编译的确类替换旧的就行，后面的程序就执行新类中的代码。这也是由各种应用服务器的独有的类加载器层次实现的。那如何在我们的程序中也实现这种热加载功能呢？即要在虚拟机不关闭的情况下(比如一个)，换个类，JVM 就知道加载这个新类，执行新类中的逻辑呢？下面就简单演示这样一个热加载的例子，首先大致了解一下类加载器。 标准 Java 启动器的类加载器层次 1. 引导类加载器(bootstrap):   加载内核 API，如 rt.jar(java.lang、java.io 等) 2. 扩展类加载器(extension):   加载的默认扩展来自于 jre/lib/ext 3. 系统类加载器(system):       类路径上的类，如 com.unmi.* 说明：这只是标准 Java 启动器运行程序时的类加载器层次，像应用服务器中的类加载器通常会多一两层，也是在这个基础上的延伸。上面的类加载层次存在自上而下的委托关系，委托加载不在这里细讲。 类加载器的规则有三 1. 一致性规则：类加载器不能多次加载同一个类 2. 委托规则  ：在加载一个类之前，类加载器总参考父类加载器 3. 可见性规则：类只能看到由其类加载器的委托加载的其他类，委托是类的加载器及其所有父类加载器的递归集。(这个规则可能不太好理解，要举个例子就很容易理解的，这里也不细说) 实际的例子演示热加载 1. 建立工程，编写代码 前面铺垫的应该够厚了，开始用个例子来说明感受类的热加载(又名热部署 Hot Deployment)。这个例子采用 Eclipse 来做，首先要建立两个普通的 Java 工程，分别是 TestHotDeployInf 和 TestHotDeployImpl。让 TestHotDeployImpl 依赖于 TestHotDeployInf 工程，即在 TestHotDeployImpl 的 Build Path 中，Projects 标签页里把 TestHotDeployInf 工程选进来，因为编译 TestHotDeployImpl 中的类要用到 [...]]]></description>
		<wfw:commentRss>http://unmi.cc/simple-java-hot-deployment/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>有关于 JVM 的垃圾收集(一)</title>
		<link>http://unmi.cc/about-jvm-1</link>
		<comments>http://unmi.cc/about-jvm-1#comments</comments>
		<pubDate>Tue, 21 Oct 2008 06:18:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[gc]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/%e6%9c%89%e5%85%b3%e4%ba%8e-jvm-%e7%9a%84%e5%9e%83%e5%9c%be%e6%94%b6%e9%9b%86%e4%b8%80</guid>
		<description><![CDATA[Java 中使用 new、newarray、anewarray 和 multianewarray 指令来创建的对象，当这些对象不再使用时由垃圾收集来释放。那么 反序列化等都是间接使用了前面的某个指令, clone()  是个本地方法？ JVM 规范不需要任何特定的垃圾收集技术，甚至也没要求有垃圾收集机制。大概只是说不需要手工释放内存，具体怎么实现各 JVM 自行决定。 GC 除了释放不再被引用的对象，还要处理堆碎片，整理出连续的空闲空间才能放得下新的对象。不至于出现总的空闲空间足够，但碎片太多而报出 "Out of Memory" 的异常。 GC 有两个好处：一个是提高了生产率，不用埋头于 Memory Link 的有时甚至是逐行的检查；二，GC 也是 Java 安全策略的一部分，有了它不至于因错误的释放内存而导至 JVM 崩溃。但是 GC 的一个潜在缺陷影响了程序的性能，它需要一直在后台不时的做些事情，而且实时性也有所欠缺。 垃圾收集算法 GC 算法要做两件基本的事情：1. 检测出垃圾对象；2. 回收垃圾对象，释放相应堆空间。垃圾检测一般是先建立一个根对象集合，其他对象要是从根对象起可触及就是活的，无法到达的就是垃圾。这里的根对象的认定就有些讲究的，不同的 JVM 的看法不完全一致，但总是会包含局部变量中的对象引用和栈帧的操作数栈(以及类变量中的引用)。 另一个根对象的来源是被加载的类的常量池中的对象引用。类的常量池中的字符串包括有类名、超类名、超接口名、字段名、字段特征签名、方法名、方法特征签名 还有一个来源是传递到方法中的、没有被本地方法“释放”的对象引用(根据本地方法接口，本地方法可以通过简单的返回来释放引用，或者显式的调用一个回调函数来释放传递来的引用，或是这两者的结合)。 再一个潜在的根对象来源是，JVM 运行时数据区中从垃圾收集器的堆中分配的部分。某些实现中，方法区中的类数据本身可能被存放在使用垃圾收集器的堆中，以便使用和释放对象同样的垃圾收集算法来检测和卸载不再被引用的类。 在某些 JVM 实现中，像基本类型，如一个 int 如果被解释为一个本地指针，那它就是指向堆中的一个对象，但是保守的垃圾收集器对这种基本类型引用的堆中的对象不处理。 区别活动对象和垃圾的两个基本方法是引用计数和跟踪。 引用计数收集器 引用计数是垃圾收集的早期策略，这种方法时堆中的每个对象都有一个引用计数。当对象创建并赋给一个变量时，引用计数为 1。每次赋给别的变量时，引用计数加 1，当对象的引用超过了生存期或指向到了新值(如果引用置为 null)，对象的引用计减 1。这样对象的引用计数为 0 [...]]]></description>
		<wfw:commentRss>http://unmi.cc/about-jvm-1/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>明明白白Unsupported major.minor version 49.0的错误</title>
		<link>http://unmi.cc/unsupported-major-minor-version-49-0-inside</link>
		<comments>http://unmi.cc/unsupported-major-minor-version-49-0-inside#comments</comments>
		<pubDate>Mon, 03 Dec 2007 19:03:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[49.0]]></category>
		<category><![CDATA[major]]></category>
		<category><![CDATA[minor]]></category>
		<category><![CDATA[Unsupported]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/%e6%98%8e%e6%98%8e%e7%99%bd%e7%99%bdunsupported-major-minor-version-49-0%e7%9a%84%e9%94%99%e8%af%af</guid>
		<description><![CDATA[一：要解决的问题 我们在尝鲜 JDK1.5 的时候，相信不少人遇到过 Unsupported major.minor version 49.0 错误，当时定会茫然不知所措。因为刚开始那会儿，网上与此相关的中文资料还不多，现在好了，网上一找就知道是如何解决，大多会告诉你要使用 JDK 1.4 重新编译。那么至于为什么，那个 major.minor 究竟为何物呢？这就是本篇来讲的内容，以使未错而先知。 我觉得我是比较幸运的，因为在遇到那个错误之前已研读过《深入 Java 虚拟机》第二版，英文原书名为《Inside the Java Virtual Machine》( Second Edition)，看时已知晓 major.minor 藏匿于何处，但没有切身体会，待到与 Unsupported major.minor version 49.0 真正会面试，正好是给我验证了一个事实。 首先我们要对 Unsupported major.minor version 49.0 建立的直接感觉是：JDK1.5 编译出来的类不能在 JVM 1.4 下运行，必须编译成 JVM 1.4 下能运行的类。(当然，也许你用的还是 JVM 1.3 或 JVM 1.2，那么就要编译成目标 JVM 能认可的类)。这也解决问题的方向。 二：major.minor 栖身于何处 何谓 major.minor，且又居身于何处呢？先感性认识并找到 major.minor 来。 [...]]]></description>
		<wfw:commentRss>http://unmi.cc/unsupported-major-minor-version-49-0-inside/feed</wfw:commentRss>
		<slash:comments>34</slash:comments>
		</item>
		<item>
		<title>Retrotranslator让你用JDK1.5的特性写出的代码能在JVM1.4中运行</title>
		<link>http://unmi.cc/retrotranslator-jdk15-run-in-jvm14</link>
		<comments>http://unmi.cc/retrotranslator-jdk15-run-in-jvm14#comments</comments>
		<pubDate>Thu, 17 May 2007 08:47:00 +0000</pubDate>
		<dc:creator>Unmi</dc:creator>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[Jdk]]></category>
		<category><![CDATA[Retrotranslator]]></category>

		<guid isPermaLink="false">http://unmi.cc/uncategorized/retrotranslator%e8%ae%a9%e4%bd%a0%e7%94%a8jdk1-5%e7%9a%84%e7%89%b9%e6%80%a7%e5%86%99%e5%87%ba%e7%9a%84%e4%bb%a3%e7%a0%81%e8%83%bd%e5%9c%a8jvm1-4%e4%b8%ad%e8%bf%90%e8%a1%8c</guid>
		<description><![CDATA[JDK1.5出来多年了(2004年10月正式发行)，就连6.0正式版在 http://java.sun.com上已是赫然在目，紧跟着的各应用服务器和 Java IDE 厂商的都准备就绪. 可是相信很多开发者跟我一样却碍于公司用的是老版本的应用服务器，如WebSphere Application Server,，WebLogic等只能支持到1.4的JDK，要升级应用服务器成本和风险都有担心，所以项目中只能用1.4 的JDK，一直无法体验到 JDK 1.5 的新特性带来的便利． 有些同事机器里一直还是躺着 JDK 1.4，我可能比他们好一点就是直接装了一个 JDK 1.5，然后在 Java IDE 中设置编译器的 Compiler compliance level为 1.4（实质就是javac –target 1.4）．这样避免了用JDK1.5编译的Class 放在1.4的JVM中运行出现49.0的字节码版本太高的错误，这样做只不是50步和100步的差距，照例用不了JDK1.5 的新特性． 我一直在探索：能不能使用JDK1.5的特性，然后让生成的字节码能在1.4的JVM下运行．如是果是仅仅换掉应用服务所用的JDK恐怕是会出很多问题的． 也算是功夫不负有心人啊，时至今日终于在网上找着了一个叫做 Retrotranslator 的工具，开源的，在 SourceForge http://sourceforge.net/projects/retrotranslator，当前版本是1.2.1．这个工具正好能满足我的需求．进到那个下载页面，你只要下载 Retrotranslator-1.2.1-bin.zip，其中包含了 retrotranslator-runtime-1.1.1-bundle.jar 字节码转换之后，运行时需要这个包来支持 retrotranslator-transformer-1.2.1-bundle.jar 转换字节码用，如用命令转换或用ant来转换需要这个包 而且还有一个 backport-util-concurrent-3.0.jar 大概是用新的并发机制运行时需要依赖这个包 Retrotranslator实质上是一个基于ASM 框架的字节码转换工具，如果要看它详细的使用帮助，请见页面　http://retrotranslator.sourceforge.net/． 使用 Retrotranslator 可以让你使用的JDK1.5的特征有泛型、注解、泛型和注解的反射、枚举、自动装/拆箱、增强的循环、变参、协变式返回类型、格式化输出、静态引入、新的并发机制、增强的集合框架。（见What Java 5 features are supported?） 还能使用新的类和新的方法，如 StringBuilder 等，见What [...]]]></description>
		<wfw:commentRss>http://unmi.cc/retrotranslator-jdk15-run-in-jvm14/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Database Caching 12/81 queries in 0.038 seconds using disk: basic
Object Caching 3832/3981 objects using disk: basic

Served from: unmi.cc @ 2012-02-23 07:45:57 -->
