Jiang's profileN.SpaceBlogLists Tools Help

Blog


    June 25

    Google的逆袭(Z,原名“用数据说话,看Google 怎样被陷害”)

    转自新浪blog: http://blog.sina.com.cn/s/blog_60676a3f0100e0xk.html

    近日,央视爆出谷歌搜索出现大量黄色词条的信息。一个引起舆论强烈反响的例子是,在谷歌搜索“儿子”竟然也能搜索到黄色词条。那么,事情是怎么发生的呢?

    下面我们来看谷歌是如何被陷害的:众所周知,谷歌关键词提醒是计算机自动摘取最近最流行的关键词来生成的。于是某些人利用这一点,大量在谷歌上搜索黄色词汇,陷害了谷歌。
    在谷歌搜索趋势图,Google Insights for Search,以及一些第三方的统计数据中,可以看到:

    在央视曝光谷歌之前7天:
    1.有人故意在谷歌大量搜索黄色词汇,使单日黄色词汇搜索量同比猛增 5950% ,单月
    搜索总量与上月相比增幅达数千倍
    2.这些搜索量100%来自北京
    3.这些搜索量几乎呈线性急剧上升,理论上这些瞬时搜索量应该服从正态分布并是突发性
    的,换句话说,这是有人故意为之。

    以下再附上几张类似图表,请注意峰值全部在6月17日,即CCTV节目(6月18日)播出的前一天。

    (全年统计)

    (本月统计)

    为做对比,说明搜索引擎的统计应该是什么样子,我来附上一张对关键词“天气预报”的搜索统计图表,从图中我们可以看到,全年搜索量应该大致呈均匀分布,考虑到搜索引擎的普及使用,会有一个逐渐升高的趋势,但绝不可能出现在某个月份呈直线上升的情况。

    那么,还有一种可能,是不是北京的人们在6月份,由于夏天到来,荷尔蒙分泌过多,导致对“儿子母亲不正当关系”这样的黄色词汇搜索过多呢?我们且来看这张对关键词“日本女优”的搜索统计图表,

    可以看到,对关键词“日本女优”的搜索量全年大致呈均匀分布,甚至在近期有下降的趋势。那么,这种近期全民荷尔蒙分泌过多的情况也应该被排除了。并不是说对所有黄色信息都有大量的搜索需求。搜索数量呈急剧上升的关键词,只局限在媒体大书特书的几个词汇之中,特别要注意的是其急剧上升阶段和峰值都在媒体报道之前,显然,这不是自然的结果,那么,答案是什么呢?是谁让谷歌如此低俗?

    March 25

    前田约翰《简单法则》

    第一,减少,就是说,达到简单的最简单方法,就是要有所割舍,割舍一些没用的功能、多余的部分,就能简单许多。
    第二,组织,妥善组织能使复杂的系统显得比较简单,这就好比合理使用一张写字台。
    第三,时间,节省时间也会让人感觉简单(虽然这种一时的简单不一定是真正的简单)。
    第四,学习,知识、经验的积累能帮助人们把某些事物变得更为简捷。
    第五,差异,简单和复杂相辅相成,没有复杂的对比反差,简单就不能更好地显现。
    第六,背景,简单的周边事物决非无关紧要,它有助于形成一种简单的氛围,让人感觉到简单。
    第七,感情,感情的寄托也有助于简单。
    第八,信任,要对一些简单的事物报以必要的信任。
    第九,失败,要相信有些事物不可能简单,不是所有东西都适合简单。
    第十,单一,简单就是要求减少形式的、无意义的,增加有意义的。

    前田约翰简介:
    前田约翰(John Maeda)世界知名的图像设计师、视觉艺术家、电脑科技专家,也是麻省理工学院媒体实验室的教授。前田约翰在艺术上的贡献也不容忽视,他得奖无数,例如:美国设计界最高荣誉Smithsonian 杂志的国家设计奖(2001年)、日本朝日设计奖(2002年)、德国Raymond Loewy 基金会奖(2005年)、戴姆勒克莱斯勒设计奖(2000年)等等。他曾在巴黎、纽约、伦敦、旧金山、东京、大阪等地举办过多次个人展览,深获好评,他的作品也被纽约现代美术馆,旧金山现代美术馆、史密森尼机构的国家设计美术馆收藏。

    February 02

    调整 Java 虚拟机 - zt

    http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/tprf_tunejvm.html

     

    调整 Java 虚拟机

    应用程序服务器是一个 Java 进程,它需要 Java 虚拟机(JVM)才能运行以及支持它所运行的 Java 应用程序。在配置应用程序服务器的过程中,可以对设置进行微调以改善系统对 JVM 的使用方式。

    关于本任务

    JVM 为基于 Java 的应用程序提供了运行时执行环境。WebSphere Application Server 是 JVM 运行时环境与基于 Java 的服务器运行时的组合。它可以在不同 JVM 提供程序提供的 JVM 上运行。要确定正在运行 Application Server 的 JVM 的提供程序,请从 WebSphere Application Server 的 app_server_root/java/bin 目录中发出 java -fullversion 命令。您也可以检查其中一个服务器的 SystemOut.log。当应用程序服务器启动时,Websphere Application Server 会将关于 JVM 的信息(包括 JVM 提供程序信息)写入此日志文件。

    从调整 JVM 的观点看,有两种主要的 JVM 类型:

    • IBM JVM
    • 基于 Sun HotSpot 的 JVM,其中包括 Solaris 上的 Sun HotSpot JVM 以及 HP 的 JVM for HP-UX

    尽管 JVM 调整操作随 JVM 提供程序的不同而有所变化,但一般的调整概念适用于所有 JVM。这些一般的概念包括:

    • 编译器调整。在服务器运行时期间,所有 JVM 都使用即时(JIT)编译器来将 Java 字节码编译为本机指令。
    • Java 内存或堆调整。JVM 内存管理功能(即垃圾回收)为提高 JVM 性能提供了其中一种最大的可能性。
    • 类装入调整。
    过程
    • 优化启动性能和运行时性能

      在某些环境中,优化 WebSphere Application Server 的启动性能比优化运行时性能更重要。在另一些环境中,优化运行时性能更为重要。缺省情况下,IBM JVM 是针对运行时性能进行优化的,而基于 HotSpot 的 JVM 是针对启动性能进行优化的。

      Java JIT 编译器在很大程度上决定了是优化启动性能还是优化运行时性能。编译器使用的初始优化级别影响编译类方法所耗用的时间以及启动服务器所耗用的时间。为了提高启动速度,可以降低编译器所使用的初始优化级别。这意味着,由于现在使用较低的优化级别来编译类方法,所以应用程序的运行时性能可能会下降。

      因为编译器在运行时执行阶段会根据自己的判断来重新编译类方法以提高性能,所以,很难提供一个有关特定的运行时性能影响的说明。最终,应用程序的持续时间是影响运行时性能下降程度的主要原因。运行时间较短的应用程序的方法被重新编译的可能性较高。运行时间较长的应用程序的方法被重新编译的可能性较低。IBM JVM 的缺省设置是使用高优化级别来执行初始编译。如果需要更改此行为,可以使用以下 IBM JVM 选项:

      -Xquickstart

      此设置影响 IBM JVM 使用较低优化级别来编译类方法的方式,这将提高服务器启动速度,但会使运行时性能下降。缺省情况下,如果未指定此参数,IBM JVM 最初将使用较高的初始优化级别来执行编译。此设置能够提高运行时性能,但会减慢服务器启动速度。

      缺省值:
      高初始编译器优化级别

      建议值:
      高初始编译器优化级别

      用法:
      -Xquickstart 可以加快服务器启动速度。

      基于 Sun 的 Hotspot 技术的 JVM 最初使用低优化级别来编译类方法。使用下列 JVM 选项来更改此行为:

      -server

      基于 Sun 的 Hotspot 技术的 JVM 最初使用低优化级别来编译类方法。这些 JVM 使用简单编译器和能够进行优化的 JIT 编译器。通常情况下,使用简单 JIT 编译器。然而,可以通过设置此选项来使用能够执行优化的编译器。此更改将显著提高服务器的性能,但使用能够执行优化的编译器时,服务器的预备时间将会较长。

      缺省值:
      简单编译器

      建议值:
      能够执行优化的编译器

      用法:
      -server 启用能够执行优化的编译器。

    • 设置堆大小 以下命令行参数对于设置堆大小来说很有用。
      • -Xms

        此设置控制 Java 堆的初始大小。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。对于某些应用程序来说,此选项的缺省设置可能会太低,从而导致发生大量小型垃圾回收。

        缺省值:
        256 MB

        建议值:
        随工作负载的不同而有所变化,但高于缺省值。

        用法:
        -Xms256m 将初始堆大小设置为 256 兆字节

      • -Xmx

        此设置控制 Java 堆的最大大小。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。对于某些应用程序来说,此选项的缺省设置可能会太低,从而导致发生大量小型垃圾回收。

        缺省值:
        512 MB

        建议值:
        随工作负载的不同而有所变化,但高于缺省值。

        用法:
        -Xmx512m 将最大堆大小设置为 512 兆字节

      • -Xlp

        此设置可以与 IBM JVM 配合使用,以使用大页来分配堆。然而,如果使用此设置,则必须将操作系统配置为支持大页。使用大页可以降低 CPU 跟踪堆内存时的开销,并且还允许创建较大的堆。

        请参阅调整操作系统 以了解有关调整操作系统的更多信息。

      应该指定的堆大小取决于不同时段的堆使用情况。在堆大小频繁更改的情况下,对 Xms 和 Xmx 参数指定相同的值可以提高性能。

    • 调整 IBM JVM 的垃圾回收器。

      使用 Java -X 选项来查看内存选项列表。

      • -Xgcpolicy

        将 gcpolicy 设置为 optthruput 会禁用并发标记。如果没有暂停时间问题(表现为应用程序响应时间不规律),则应该使用此选项来实现最大吞吐量。将 gcpolicy 设置为 optavgpause 会使用缺省值来启用并发标记。此设置将减少由正常垃圾回收所引起的应用程序响应时间不规律情况。然而,此选项可能会降低整体吞吐量。

        缺省值:
        optthruput

        建议值:
        optthruput

        用法:
        Xgcpolicy:optthruput

      • -Xnoclassgc

        缺省情况下,当一个类没有任何活动实例时,JVM 就会从内存中卸载该类,但是这样会使性能下降。如果关闭类垃圾回收,就可以消除由于多次装入和卸载同一个类而造成的开销。

        如果不再需要某个类,则该类在堆中所占用的空间通常将用于创建新对象。但是,如果应用程序通过创建类的新实例来处理请求,并且该应用程序的请求是随机出现的,则可能会发生以下情况:先前请求者完成后,正常的类垃圾回收将通过释放这个类占用的堆空间来清除这个类,但当下一个请求出现时,又必须将这个类重新实例化。在这种情况下,您可能想使用此选项来禁用类垃圾回收。

        缺省值:
        启用类垃圾回收

        建议值:
        禁用类垃圾回收

        用法:
        Xnoclassgc 禁用类垃圾回收

      有关其他信息,请参阅下列 DeveloperWorks 文章:

    • [Solaris] 调整 Sun JVM 的垃圾回收器

      在 Solaris 平台上,WebSphere Application Server 在 Sun Hotspot JVM 上运行,而不是在 IBM JVM 上运行。对 Sun JVM 使用正确的调整参数以利用其性能优化功能十分重要。

      Sun Hotspot JVM 依靠分代垃圾回收来实现最佳性能。下列命令行参数对于调整垃圾回收来说非常有用。

      • -XX:SurvivorRatio

        将 Java 堆划分为旧对象(长生命周期对象)区域和新对象区域。新对象区域进一步细分为两部分,第一部分用于分配给新对象(初始区域),第二部分存放那些经过其前几次垃圾回收之后、但在被提升为旧对象之前仍在使用中的新对象(幸存者空间)。幸存者比率是堆的新对象区域中初始区域与幸存者空间的比率。增大此设置将针对需要创建大量对象但仅保留少量对象的应用程序优化 JVM。与其他应用程序相比,WebSphere Application Server 会生成更多中等生命周期对象和长生命周期对象,因此,应该将此设置设置为小于缺省值。

        缺省值:
        32

        建议值:
        16

        用法:
        -XX:SurvivorRatio=16

      • -XX:PermSize

        为永久生成对象保留的堆区域存储 JVM 的所有反射数据。对于动态地装入和卸载大量类的应用程序来说,应该增大此大小以优化它们的性能。通过将此参数设置为 128MB,可以消除增大此部分堆所需的开销。

        建议值:
        128 MB

        用法:
        XX:PermSize=128m 将 perm 大小设置为 128 兆字节。

      • -Xmn

        此设置控制允许新生成的对象在堆中耗用的空间量。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。此参数的缺省设置通常过低,这将导致执行大量的小型垃圾回收操作。如果将此参数设置得过高,可能会导致 JVM 仅执行大型(全面)垃圾回收。这些垃圾回收操作通常会耗时几秒钟,这将严重影响服务器的整体性能。您必须保持将此参数设置为小于整个堆大小的一半,以避免这种情况出现。

        缺省值:
        2228224 字节

        建议值:
        大约整个堆大小的 1/4

        用法:
        -Xmn256m 将大小设置为 256 兆字节。

      • -Xnoclassgc

        缺省情况下,当一个类没有任何活动实例时,JVM 就会从内存中卸载该类,但是这样会使性能下降。如果关闭类垃圾回收,就可以消除由于多次装入和卸载同一个类而造成的开销。

        如果不再需要某个类,则该类在堆中所占用的空间通常将用于创建新对象。但是,如果应用程序通过创建类的新实例来处理请求,并且该应用程序的请求是随机出现的,则可能会发生以下情况:先前请求者完成后,正常的类垃圾回收将通过释放这个类占用的堆空间来清除这个类,但当下一个请求出现时,又必须将这个类重新实例化。在这种情况下,您可能想使用此选项来禁用类垃圾回收。

        缺省值:
        启用类垃圾回收

        建议值:
        禁用类垃圾回收

        用法:
        Xnoclassgc 禁用类垃圾回收

      有关调整 Sun JVM 的其他信息,请参阅 Java HotSpot VM 的性能文档

    • [HP-UX] 调整 HP JVM 的垃圾回收器

      HP JVM 依靠分代垃圾回收来实现最佳性能。下列命令行参数对于调整垃圾回收来说非常有用。

      • -Xoptgc

        此设置针对包含许多短生命周期对象的应用程序优化 JVM。如果未指定此参数,则 JVM 通常执行大型(全面)垃圾回收。全面垃圾回收会花费几秒钟时间,这将显著影响服务器性能。

        缺省值:
        off

        建议值:
        on

        用法:
        -Xoptgc 启用优化的垃圾回收。

      • -XX:SurvivorRatio

        将 Java 堆划分为旧对象(长生命周期对象)区域和新对象区域。新对象区域进一步细分为两部分,第一部分用于分配给新对象(初始区域),第二部分存放那些经过其前几次垃圾回收之后、但在被提升为旧对象之前仍在使用中的新对象(幸存者空间)。幸存者比率是堆的新对象区域中初始区域与幸存者空间的比率。增大此设置将针对需要创建大量对象但仅保留少量对象的应用程序优化 JVM。与其他应用程序相比,WebSphere Application Server 会生成更多中等生命周期对象和长生命周期对象,因此,应该将此设置设置为小于缺省值。

        缺省值:
        32

        建议值:
        16

        用法:
        -XX:SurvivorRatio=16

      • -XX:PermSize

        为永久生成对象保留的堆区域存储 JVM 的所有反射数据。对于动态地装入和卸载大量类的应用程序来说,应该增大此大小以优化它们的性能。通过将此参数指定为 128 兆字节,可以消除增大此部分堆所需的开销。

        缺省值:
        0

        建议值:
        128 兆字节

        用法:
        -XX:PermSize=128m 将 PermSize 设置为 128 兆字节

      • -XX:+ForceMmapReserved

        缺省情况下,Java 堆以“惰性交换”方式进行分配。在此方式下,将根据需要来分配内存页,这样可以节省交换空间,但是也将强制使用 4KB 页。在大型堆系统中,这种内存分配方式允许堆包含数以十万计的页。此命令禁用“惰性交换”并允许操作系统使用较大的内存页,从而优化对构成 Java 堆的内存的访问。

        缺省值:
        off

        建议值:
        on

        用法:
        -XX:+ForceMmapReserved 将禁用“惰性交换”。

      • -Xmn

        此设置控制允许新生成的对象在堆中耗用的空间量。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。此参数的缺省设置通常过低,这将导致执行大量的小型垃圾回收操作。

        缺省值:
        没有缺省值

        建议值:
        大约整个堆大小的 3/4

        用法:
        -Xmn768m 将大小设置为 768 兆字节

      • 虚拟页大小

        通过将 Java 虚拟机的指令页大小和数据页大小设置为 64MB,可以提高性能。

        缺省值:
        4MB

        建议值:
        64MB

        用法:
        使用以下命令。命令输出提供了进程可执行文件的当前操作系统特征:

        chatr +pi64M +pd64M /opt/WebSphere/
        AppServer/java/bin/PA_RISC2.0/
        native_threads/java 
      • -Xnoclassgc

        缺省情况下,当一个类没有任何活动实例时,JVM 就会从内存中卸载该类,但是这样会使性能下降。如果关闭类垃圾回收,就可以消除由于多次装入和卸载同一个类而造成的开销。

        如果不再需要某个类,则该类在堆中所占用的空间通常将用于创建新对象。但是,如果应用程序通过创建类的新实例来处理请求,并且该应用程序的请求是随机出现的,则可能会发生以下情况:先前请求者完成后,正常的类垃圾回收将通过释放这个类占用的堆空间来清除这个类,但当下一个请求出现时,又必须将这个类重新实例化。在这种情况下,您可能想使用此选项来禁用类垃圾回收。

        缺省值:
        启用类垃圾回收

        建议值:
        禁用类垃圾回收

        用法:
        Xnoclassgc 禁用类垃圾回收

      有关调整 HP 虚拟机的其他信息,请参阅 Java 技术软件 HP-UX 11i

    • [HP-UX] 调整 HP 的 JVM for HP-UX 设置下列选项以提高应用程序性能:
      -XX:SchedulerPriorityRange=SCHED_NOAGE 
      -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.DevPollSelectorProvider 
      -XX:-ExtraPollBeforeRead
      

    调整 Java 虚拟机 - zt

    http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/tprf_tunejvm.html

     

    调整 Java 虚拟机

    应用程序服务器是一个 Java 进程,它需要 Java 虚拟机(JVM)才能运行以及支持它所运行的 Java 应用程序。在配置应用程序服务器的过程中,可以对设置进行微调以改善系统对 JVM 的使用方式。

    关于本任务

    JVM 为基于 Java 的应用程序提供了运行时执行环境。WebSphere Application Server 是 JVM 运行时环境与基于 Java 的服务器运行时的组合。它可以在不同 JVM 提供程序提供的 JVM 上运行。要确定正在运行 Application Server 的 JVM 的提供程序,请从 WebSphere Application Server 的 app_server_root/java/bin 目录中发出 java -fullversion 命令。您也可以检查其中一个服务器的 SystemOut.log。当应用程序服务器启动时,Websphere Application Server 会将关于 JVM 的信息(包括 JVM 提供程序信息)写入此日志文件。

    从调整 JVM 的观点看,有两种主要的 JVM 类型:

    • IBM JVM
    • 基于 Sun HotSpot 的 JVM,其中包括 Solaris 上的 Sun HotSpot JVM 以及 HP 的 JVM for HP-UX

    尽管 JVM 调整操作随 JVM 提供程序的不同而有所变化,但一般的调整概念适用于所有 JVM。这些一般的概念包括:

    • 编译器调整。在服务器运行时期间,所有 JVM 都使用即时(JIT)编译器来将 Java 字节码编译为本机指令。
    • Java 内存或堆调整。JVM 内存管理功能(即垃圾回收)为提高 JVM 性能提供了其中一种最大的可能性。
    • 类装入调整。
    过程
    • 优化启动性能和运行时性能

      在某些环境中,优化 WebSphere Application Server 的启动性能比优化运行时性能更重要。在另一些环境中,优化运行时性能更为重要。缺省情况下,IBM JVM 是针对运行时性能进行优化的,而基于 HotSpot 的 JVM 是针对启动性能进行优化的。

      Java JIT 编译器在很大程度上决定了是优化启动性能还是优化运行时性能。编译器使用的初始优化级别影响编译类方法所耗用的时间以及启动服务器所耗用的时间。为了提高启动速度,可以降低编译器所使用的初始优化级别。这意味着,由于现在使用较低的优化级别来编译类方法,所以应用程序的运行时性能可能会下降。

      因为编译器在运行时执行阶段会根据自己的判断来重新编译类方法以提高性能,所以,很难提供一个有关特定的运行时性能影响的说明。最终,应用程序的持续时间是影响运行时性能下降程度的主要原因。运行时间较短的应用程序的方法被重新编译的可能性较高。运行时间较长的应用程序的方法被重新编译的可能性较低。IBM JVM 的缺省设置是使用高优化级别来执行初始编译。如果需要更改此行为,可以使用以下 IBM JVM 选项:

      -Xquickstart

      此设置影响 IBM JVM 使用较低优化级别来编译类方法的方式,这将提高服务器启动速度,但会使运行时性能下降。缺省情况下,如果未指定此参数,IBM JVM 最初将使用较高的初始优化级别来执行编译。此设置能够提高运行时性能,但会减慢服务器启动速度。

      缺省值:
      高初始编译器优化级别

      建议值:
      高初始编译器优化级别

      用法:
      -Xquickstart 可以加快服务器启动速度。

      基于 Sun 的 Hotspot 技术的 JVM 最初使用低优化级别来编译类方法。使用下列 JVM 选项来更改此行为:

      -server

      基于 Sun 的 Hotspot 技术的 JVM 最初使用低优化级别来编译类方法。这些 JVM 使用简单编译器和能够进行优化的 JIT 编译器。通常情况下,使用简单 JIT 编译器。然而,可以通过设置此选项来使用能够执行优化的编译器。此更改将显著提高服务器的性能,但使用能够执行优化的编译器时,服务器的预备时间将会较长。

      缺省值:
      简单编译器

      建议值:
      能够执行优化的编译器

      用法:
      -server 启用能够执行优化的编译器。

    • 设置堆大小 以下命令行参数对于设置堆大小来说很有用。
      • -Xms

        此设置控制 Java 堆的初始大小。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。对于某些应用程序来说,此选项的缺省设置可能会太低,从而导致发生大量小型垃圾回收。

        缺省值:
        256 MB

        建议值:
        随工作负载的不同而有所变化,但高于缺省值。

        用法:
        -Xms256m 将初始堆大小设置为 256 兆字节

      • -Xmx

        此设置控制 Java 堆的最大大小。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。对于某些应用程序来说,此选项的缺省设置可能会太低,从而导致发生大量小型垃圾回收。

        缺省值:
        512 MB

        建议值:
        随工作负载的不同而有所变化,但高于缺省值。

        用法:
        -Xmx512m 将最大堆大小设置为 512 兆字节

      • -Xlp

        此设置可以与 IBM JVM 配合使用,以使用大页来分配堆。然而,如果使用此设置,则必须将操作系统配置为支持大页。使用大页可以降低 CPU 跟踪堆内存时的开销,并且还允许创建较大的堆。

        请参阅调整操作系统 以了解有关调整操作系统的更多信息。

      应该指定的堆大小取决于不同时段的堆使用情况。在堆大小频繁更改的情况下,对 Xms 和 Xmx 参数指定相同的值可以提高性能。

    • 调整 IBM JVM 的垃圾回收器。

      使用 Java -X 选项来查看内存选项列表。

      • -Xgcpolicy

        将 gcpolicy 设置为 optthruput 会禁用并发标记。如果没有暂停时间问题(表现为应用程序响应时间不规律),则应该使用此选项来实现最大吞吐量。将 gcpolicy 设置为 optavgpause 会使用缺省值来启用并发标记。此设置将减少由正常垃圾回收所引起的应用程序响应时间不规律情况。然而,此选项可能会降低整体吞吐量。

        缺省值:
        optthruput

        建议值:
        optthruput

        用法:
        Xgcpolicy:optthruput

      • -Xnoclassgc

        缺省情况下,当一个类没有任何活动实例时,JVM 就会从内存中卸载该类,但是这样会使性能下降。如果关闭类垃圾回收,就可以消除由于多次装入和卸载同一个类而造成的开销。

        如果不再需要某个类,则该类在堆中所占用的空间通常将用于创建新对象。但是,如果应用程序通过创建类的新实例来处理请求,并且该应用程序的请求是随机出现的,则可能会发生以下情况:先前请求者完成后,正常的类垃圾回收将通过释放这个类占用的堆空间来清除这个类,但当下一个请求出现时,又必须将这个类重新实例化。在这种情况下,您可能想使用此选项来禁用类垃圾回收。

        缺省值:
        启用类垃圾回收

        建议值:
        禁用类垃圾回收

        用法:
        Xnoclassgc 禁用类垃圾回收

      有关其他信息,请参阅下列 DeveloperWorks 文章:

    • [Solaris] 调整 Sun JVM 的垃圾回收器

      在 Solaris 平台上,WebSphere Application Server 在 Sun Hotspot JVM 上运行,而不是在 IBM JVM 上运行。对 Sun JVM 使用正确的调整参数以利用其性能优化功能十分重要。

      Sun Hotspot JVM 依靠分代垃圾回收来实现最佳性能。下列命令行参数对于调整垃圾回收来说非常有用。

      • -XX:SurvivorRatio

        将 Java 堆划分为旧对象(长生命周期对象)区域和新对象区域。新对象区域进一步细分为两部分,第一部分用于分配给新对象(初始区域),第二部分存放那些经过其前几次垃圾回收之后、但在被提升为旧对象之前仍在使用中的新对象(幸存者空间)。幸存者比率是堆的新对象区域中初始区域与幸存者空间的比率。增大此设置将针对需要创建大量对象但仅保留少量对象的应用程序优化 JVM。与其他应用程序相比,WebSphere Application Server 会生成更多中等生命周期对象和长生命周期对象,因此,应该将此设置设置为小于缺省值。

        缺省值:
        32

        建议值:
        16

        用法:
        -XX:SurvivorRatio=16

      • -XX:PermSize

        为永久生成对象保留的堆区域存储 JVM 的所有反射数据。对于动态地装入和卸载大量类的应用程序来说,应该增大此大小以优化它们的性能。通过将此参数设置为 128MB,可以消除增大此部分堆所需的开销。

        建议值:
        128 MB

        用法:
        XX:PermSize=128m 将 perm 大小设置为 128 兆字节。

      • -Xmn

        此设置控制允许新生成的对象在堆中耗用的空间量。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。此参数的缺省设置通常过低,这将导致执行大量的小型垃圾回收操作。如果将此参数设置得过高,可能会导致 JVM 仅执行大型(全面)垃圾回收。这些垃圾回收操作通常会耗时几秒钟,这将严重影响服务器的整体性能。您必须保持将此参数设置为小于整个堆大小的一半,以避免这种情况出现。

        缺省值:
        2228224 字节

        建议值:
        大约整个堆大小的 1/4

        用法:
        -Xmn256m 将大小设置为 256 兆字节。

      • -Xnoclassgc

        缺省情况下,当一个类没有任何活动实例时,JVM 就会从内存中卸载该类,但是这样会使性能下降。如果关闭类垃圾回收,就可以消除由于多次装入和卸载同一个类而造成的开销。

        如果不再需要某个类,则该类在堆中所占用的空间通常将用于创建新对象。但是,如果应用程序通过创建类的新实例来处理请求,并且该应用程序的请求是随机出现的,则可能会发生以下情况:先前请求者完成后,正常的类垃圾回收将通过释放这个类占用的堆空间来清除这个类,但当下一个请求出现时,又必须将这个类重新实例化。在这种情况下,您可能想使用此选项来禁用类垃圾回收。

        缺省值:
        启用类垃圾回收

        建议值:
        禁用类垃圾回收

        用法:
        Xnoclassgc 禁用类垃圾回收

      有关调整 Sun JVM 的其他信息,请参阅 Java HotSpot VM 的性能文档

    • [HP-UX] 调整 HP JVM 的垃圾回收器

      HP JVM 依靠分代垃圾回收来实现最佳性能。下列命令行参数对于调整垃圾回收来说非常有用。

      • -Xoptgc

        此设置针对包含许多短生命周期对象的应用程序优化 JVM。如果未指定此参数,则 JVM 通常执行大型(全面)垃圾回收。全面垃圾回收会花费几秒钟时间,这将显著影响服务器性能。

        缺省值:
        off

        建议值:
        on

        用法:
        -Xoptgc 启用优化的垃圾回收。

      • -XX:SurvivorRatio

        将 Java 堆划分为旧对象(长生命周期对象)区域和新对象区域。新对象区域进一步细分为两部分,第一部分用于分配给新对象(初始区域),第二部分存放那些经过其前几次垃圾回收之后、但在被提升为旧对象之前仍在使用中的新对象(幸存者空间)。幸存者比率是堆的新对象区域中初始区域与幸存者空间的比率。增大此设置将针对需要创建大量对象但仅保留少量对象的应用程序优化 JVM。与其他应用程序相比,WebSphere Application Server 会生成更多中等生命周期对象和长生命周期对象,因此,应该将此设置设置为小于缺省值。

        缺省值:
        32

        建议值:
        16

        用法:
        -XX:SurvivorRatio=16

      • -XX:PermSize

        为永久生成对象保留的堆区域存储 JVM 的所有反射数据。对于动态地装入和卸载大量类的应用程序来说,应该增大此大小以优化它们的性能。通过将此参数指定为 128 兆字节,可以消除增大此部分堆所需的开销。

        缺省值:
        0

        建议值:
        128 兆字节

        用法:
        -XX:PermSize=128m 将 PermSize 设置为 128 兆字节

      • -XX:+ForceMmapReserved

        缺省情况下,Java 堆以“惰性交换”方式进行分配。在此方式下,将根据需要来分配内存页,这样可以节省交换空间,但是也将强制使用 4KB 页。在大型堆系统中,这种内存分配方式允许堆包含数以十万计的页。此命令禁用“惰性交换”并允许操作系统使用较大的内存页,从而优化对构成 Java 堆的内存的访问。

        缺省值:
        off

        建议值:
        on

        用法:
        -XX:+ForceMmapReserved 将禁用“惰性交换”。

      • -Xmn

        此设置控制允许新生成的对象在堆中耗用的空间量。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。此参数的缺省设置通常过低,这将导致执行大量的小型垃圾回收操作。

        缺省值:
        没有缺省值

        建议值:
        大约整个堆大小的 3/4

        用法:
        -Xmn768m 将大小设置为 768 兆字节

      • 虚拟页大小

        通过将 Java 虚拟机的指令页大小和数据页大小设置为 64MB,可以提高性能。

        缺省值:
        4MB

        建议值:
        64MB

        用法:
        使用以下命令。命令输出提供了进程可执行文件的当前操作系统特征:

        chatr +pi64M +pd64M /opt/WebSphere/
        AppServer/java/bin/PA_RISC2.0/
        native_threads/java 
      • -Xnoclassgc

        缺省情况下,当一个类没有任何活动实例时,JVM 就会从内存中卸载该类,但是这样会使性能下降。如果关闭类垃圾回收,就可以消除由于多次装入和卸载同一个类而造成的开销。

        如果不再需要某个类,则该类在堆中所占用的空间通常将用于创建新对象。但是,如果应用程序通过创建类的新实例来处理请求,并且该应用程序的请求是随机出现的,则可能会发生以下情况:先前请求者完成后,正常的类垃圾回收将通过释放这个类占用的堆空间来清除这个类,但当下一个请求出现时,又必须将这个类重新实例化。在这种情况下,您可能想使用此选项来禁用类垃圾回收。

        缺省值:
        启用类垃圾回收

        建议值:
        禁用类垃圾回收

        用法:
        Xnoclassgc 禁用类垃圾回收

      有关调整 HP 虚拟机的其他信息,请参阅 Java 技术软件 HP-UX 11i

    • [HP-UX] 调整 HP 的 JVM for HP-UX 设置下列选项以提高应用程序性能:
      -XX:SchedulerPriorityRange=SCHED_NOAGE 
      -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.DevPollSelectorProvider 
      -XX:-ExtraPollBeforeRead
      

    Tuning Garbage Collection with the 1.4.2 JavaTM Virtual Machine

    http://java.sun.com/docs/hotspot/gc1.4.2/

    Table of Contents

    1 Introduction

    2 Generations

    2.1 Performance Considerations

    2.2 Measurement

    3 Sizing the Generations

    3.1 Total Heap

    3.2 The Young Generation

    3.2.1 Young Generation Guarantee

    4 Types of Collectors

    4.1When to Use the Throughput Collector

    4.2 The Throughput Collector

    4.2.1 Adaptive Sizing

    4.2.2 AggressiveHeap

    4.2.3 Measurements with the Throughput Collector

    4.3 When to Use the Concurrent Low Pause Collector

    4.4 The Concurrent Low Pause Collector

    4.4.1 Overhead of Concurrency

    4.4.2 Young Generation Guarantee

    4.4.3 Full Collections

    4.4.4 Floating Garbage

    4.4.5 Pauses

    4.4.6 Concurrent Phases

    4.4.7 Measurements with the Concurrent Collector

    4.4.8 Parallel Minor Collection Options with the Concurrent Collector

    4.5 When to Use the Incremental Low Pause Collector

    4.6 The Incremental Low Pause Collector

    4.6.1 Measurements with the Incremental Collector

    5 Other Considerations

    6 Conclusion

    7 Other Documentation

    7.1 Example of Output

    7.2 Frequently Asked Questions

    1 Introduction

    The JavaTM 2 Platform, Standard Edition (J2SETM platform) is used for a wide variety of applications from small applets on desktops to web services on large servers. In the J2SE platform version 1.4.1 two new garbage collectors were introduced to make a total of four garbage collectors from which to choose. How should that choice be made and what are the consequences of that choice? This document will describe some of the general features shared by all the garbage collectors. It will then discuss tuning options to take the best advantage of those features in the context of the default single-threaded, stop-the-world collector. Finally, it will discuss the specific features of the three other collectors, and discuss the criteria for choosing one of the four collectors.

    When does garbage collection performance matter to the user? For many applications it doesn't. That is, the application can perform within its specifications in the presence of garbage collection with pauses of modest frequency and duration. An example where this is not the case (when the default collector is used) would be a large application that scales well to large number of threads, processors, sockets, and a large amount of memory.

    Amdahl observed that most workloads cannot be perfectly parallelized; some portion is always sequential and does not benefit from parallelism. This is also true for the J2SE platform. In particular, virtual machines for the JavaTM platform up to and including version 1.3.1 do not have parallel garbage collection, so the impact of garbage collection on a multiprocessor system grows relative to an otherwise parallel application.

    The graph below models an ideal system that is perfectly scalable with the exception of garbage collection. The red line is an application spending only 1% of the time in garbage collection on a uniprocessor system. This translates to more than a 20% loss in throughput on 32 processor systems. At 10% of the time in garbage collection (not considered an outrageous amount of time in garbage collection in uniprocessor applications) more than 75% of throughput is lost when scaling up to 32 processors.

    GC vs. Amdahl's law

    This shows that negligible speed issues when developing on small systems may become principal bottlenecks when scaling up to large systems. However, small improvements in reducing such a bottleneck can produce large gains in performance. For a sufficiently large system it becomes well worthwhile to tune the garbage collector.

    The default collector should be the first choice for garbage collection and will be adequate for the majority of applications. Each of the other collectors have some added overhead and/or complexity, which is the price for specialized behavior. If the application doesn't need the specialized behavior of the alternate collectors, use the default collector. The exception to this rule is large applications that are heavily threaded and run on hardware with a large amount of memory and a large number of processors. For such applications, first try the aggressive heap option (-XX:+AggressiveHeap) described below.

    This document was written using the J2SE platform, version 1.4.2, on the SolarisTM Operating Environment (SPARC(R) Platform Edition) as the base platform, because it provides the most scalable hardware and software for the J2SE platform. However, the descriptive text applies to other supported platforms, including Linux, Microsoft Windows, and the Solaris Operating Environment (x86 Platform Edition), to the extent that scalable hardware is available. Although command line options are consistent across platforms, some platforms may have defaults different than those described here.

    2 Generations

    One strength of the J2SE platform is that it shields the complexity of memory allocation and garbage collection from the developer. However, once garbage collection is the principal bottleneck, it is worth understanding some aspects of this hidden implementation. Garbage collectors make assumptions about the way applications use objects, and these are reflected in tunable parameters that can be adjusted for improved performance without sacrificing the power of the abstraction.

    An object is considered garbage when it can no longer be reached from any pointer in the running program. The most straightforward garbage collection algorithms simply iterate over every reachable object. Any objects left over are then considered garbage. The time this approach takes is proportional to the number of live objects, which is prohibitive for large applications maintaining lots of live data.

    Beginning with the J2SE platform, version 1.2, the virtual machine incorporated a number of different garbage collection algorithms that are combined using generational collection. While naive garbage collection examines every live object in the heap, generational collection exploits several empirically observed properties of most applications to avoid extra work.

    The most important of these observed properties is infant mortality. The blue area in the diagram below is a typical distribution for the lifetimes of objects. The X axis is object lifetimes measured in bytes allocated. The byte count on the Y axis is the total bytes in objects with the corresponding lifetime. The sharp peak at the left represents objects that can be reclaimed (i.e., have "died") shortly after being allocated. Iterator objects, for example, are often alive for the duration of a single loop.

    histogram with collections

    Some objects do live longer, and so the distribution stretches out to the the right. For instance, there are typically some objects allocated at initialization that live until the process exits. Between these two extremes are objects that live for the duration of some intermediate computation, seen here as the lump to the right of the infant mortality peak. Some applications have very different looking distributions, but a surprisingly large number possess this general shape. Efficient collection is made possible by focusing on the fact that a majority of objects "die young".

    To optimize for this scenario, memory is managed in generations, or memory pools holding objects of different ages. Garbage collection occurs in each generation when the generation fills up. Objects are allocated in a generation for younger objects or the young generation, and because of infant mortality most objects die there. When the young generation fills up it causes a minor collection. Minor collections can be optimized assuming a high infant mortality rate. The costs of such collections are, to the first order, proportional to the number of live objects being collected. A young generation full of dead objects is collected very quickly. Some surviving objects are moved to an tenured generation. When the tenured generation needs to be collected there is a major collection that is often much slower because it involves all live objects.

    The diagram below shows minor collections occurring at intervals long enough to allow many of the objects to die between collections. It is well-tuned in the sense that the young generation is large enough (and thus the period between minor collections long enough) that the minor collection can take advantage of the high infant mortality rate. This situation can be upset by applications with unusual lifetime distributions, or by poorly sized generations that cause collections to occur before objects have had time to die.

    The default garbage collector is meant to be used by applications large and small. Its default parameters were designed to be effective for most small applications. The default parameters aren't optimal for many server applications. This leads to the central tenet of this document:

    If the garbage collector has become a bottleneck, you may wish to customize the generation sizes. Check the verbose garbage collector output, and then explore the sensitivity of your individual performance metric to the garbage collector parameters.

    The default arrangement of generations looks something like this.

    space usage by generations

    At initialization, a maximum address space is virtually reserved but not allocated to physical memory unless it is needed. The complete address space reserved for object memory can be divided into the young and tenured generations.

    The young generation consists of eden plus two survivor spaces . Objects are initially allocated in eden. One survivor space is empty at any time, and serves as a destination of the next, copying collection of any live objects in eden and the other survivor space. Objects are copied between survivor spaces in this way until they old enough to be tenured, or copied to the tenured generation.

    Other virtual machines, including the production virtual machine for the J2SE platform, version 1.2 for the Solaris Operating Environment, used two equally sized spaces for copying rather than one large eden plus two small spaces. This means the options for sizing the young generation are not directly comparable; see the Performance FAQ for an example.

    One portion of the tenured generation called the permanent generation is special because it holds all the reflective data of the virtual machine itself, such as class and method objects.

    2.1 Performance Considerations

    There are two primary measures of garbage collection performance. Throughput is the percentage of total time not spent in garbage collection, considered over long periods of time. Throughput includes time spent in allocation (but tuning for speed of allocation is generally not needed.) Pauses are the times when an application appears unresponsive because garbage collection is occurring.

    Users have different requirements of garbage collection. For example, some consider the right metric for a web server to be throughput, since pauses during garbage collection may be tolerable, or simply obscured by network latencies. However, in an interactive graphics program even short pauses may negatively affect the user experience.

    Some users are sensitive to other considerations. Footprint is the working set of a process, measured in pages and cache lines. On systems with limited physical memory or many processes, footprint may dictate scalability. Promptness is the time between when an object becomes dead and when the memory becomes available, an important consideration for distributed systems, including remote method invocation (RMI).

    In general, a particular generation sizing chooses a trade-off between these considerations. For example, a very large young generation may maximize throughput, but does so at the expense of footprint, promptness, and pause times. young generation pauses can be minimized by using a small young generation at the expense of throughput. To a first approximation, the sizing of one generation does not affect the collection frequency and pause times for another generation.

    There is no one right way to size generations. The best choice is determined by the way the application uses memory as well as user requirements. For this reason the virtual machine's default garbage collectior may not be optimal, and may be overridden by the user in the form of command line options, described below.

    2.2 Measurement

    Throughput and footprint are best measured using metrics particular to the application. For example, throughput of a web server may be tested using a client load generator, while footprint of the server might be measured on the Solaris Operating Environment using the pmap command. On the other hand, pauses due to garbage collection are easily estimated by inspecting the diagnostic output of the virtual machine itself.

    The command line argument -verbose:gc prints information at every collection. Note that the format of the -verbose:gc output is subject to change between releases of the J2SE platform. For example, here is output from a large server application:

      [GC 325407K->83000K(776768K), 0.2300771 secs]
      [GC 325816K->83372K(776768K), 0.2454258 secs]
      [Full GC 267628K->83769K(776768K), 1.8479984 secs]

    Here we see two minor collections and one major one. The numbers before and after the arrow

    325407K->83000K (in the first line)

    indicate the combined size of live objects before and after garbage collection, respectively. After minor collections the count includes objects that aren't necessarily alive but can't be reclaimed, either because they are directly alive, or because they are within or referenced from the tenured generation. The number in parenthesis

    (776768K)(in the first line)

    is the total available space, not counting the space in the permanent generation, which is the total heap minus one of the survivor spaces. The minor collection took about a quarter of a second.

    0.2300771 secs (in the first line)

    The format for the major collection in the third line is similar. The flag -XX:+PrintGCDetails prints additional information about the collections. The additional information printed with this flag is liable to change with each version of the virtual machine. The additional output with the -XX:+PrintGCDetails flag in particular changes with the needs of the development of the Java Virtual Machine. An example of the output with -XX:+PrintGCDetails for the J2SE platform, version 1.4.2 is shown here.

    [GC [DefNew: 64575K->959K(64576K), 0.0457646 secs] 196016K->133633K(261184K), 0.0459067 secs]]

    indicates that the minor collection recovered about 98% of the young generation,

    DefNew: 64575K->959K(64576K)

    and took about 46 milliseconds.

    0.0457646 secs

    The usage of the entire heap was reduced to about 51%

    196016K->133633K(261184K)

    and that there was some slight additional overhead for the collection (over and above the collection of the young generation) as indicated by the final time:

    0.0459067 secs

    The flag -XX:+PrintGCTimeStamps will additionally print a time stamp at the start of each collection.

    111.042: [GC 111.042: [DefNew: 8128K->8128K(8128K), 0.0000505 secs]111.042: [Tenured: 18154K->2311K(24576K), 0.1290354 secs] 26282K->2311K(32704K), 0.1293306 secs]

    The collection starts about 111 seconds into the execution of the application. The minor collection starts at about the same time. Additionally the information is shown for a major collection delineated by Tenured. The tenured generation usage was reduced to about 10%

    18154K->2311K(24576K)

    and took about .13 seconds.

    0.1290354 secs

    3 Sizing the Generations

    A number of parameters affect generation size. The following diagram illustrates the difference between committed space and virtual space in the heap. At initialization of the virtual machine, the entire space for the heap is reserved. The size of the space reserved can be specified with the -Xmx option. If the value of the -Xms parameter is smaller than the value of the -Xmx parameter, not all of the space that is reserved is immediately committed to the virtual machine. The uncommitted space is labeled "virtual" in this figure. The different parts of the heap (permanent generation, tenured generation, and young generation) can grow to the limit of the virtual space as needed.

    Some of the parameters are ratios of one part of the heap to another. For example the parameter NewRatio denotes the relative size of the tenured generation to the young generation. These parameters are discussed below.

    options affecting sizing

    3.1 Total Heap

    Since collections occur when generations fill up, throughput is inversely proportional to the amount of memory available. Total available memory is the most important factor affecting garbage collection performance.

    By default, the virtual machine grows or shrinks the heap at each collection to try to keep the proportion of free space to live objects at each collection within a specific range. This target range is set as a percentage by the parameters -XX:MinHeapFreeRatio=<minimum> and -XX:MaxHeapFreeRatio=<maximum>, and the total size is bounded below by -Xms and above by -Xmx . The default parameters for the Solaris Operating Environment (SPARC Platform Edition) are shown in this table:

    -XX:MinHeapFreeRatio=

    40

    -XX:MaxHeapFreeRatio=

    70

    -Xms

    3670k

    -Xmx

    64m

    With these parameters if the percent of free space in a generation falls below 40%, the size of the generation will be expanded so as to have 40% of the space free, assuming the size of the generation has not already reached its limit. Similarly, if the percent of free space exceeds 70%, the size of the generation will be shrunk so as to have only 70% of the space free as long as shrinking the generation does not decrease it below the minimum size of the generation.

    Large server applications often experience two problems with these defaults. One is slow startup, because the initial heap is small and must be resized over many major collections. A more pressing problem is that the default maximum heap size is unreasonably small for most server applications. The rules of thumb for server applications are:

    Unless you have problems with pauses, try granting as much memory as possible to the virtual machine. The default size (64MB) is often too small.

    Setting -Xms and -Xmx to the same value increases predictability by removing the most important sizing decision from the virtual machine. On the other hand, the virtual machine can't compensate if you make a poor choice.

    Be sure to increase the memory as you increase the number of processors, since allocation can be parallelized.

    A description of other virtual machine options can be found at

    http://java.sun.com/docs/hotspot/VMOptions.html

    3.2 The Young Generation

    The second most influential knob is the proportion of the heap dedicated to the young generation. The bigger the young generation, the less often minor collections occur. However, for a bounded heap size a larger young generation implies a smaller tenured generation, which will increase the frequency of major collections. The optimal choice depends on the lifetime distribution of the objects allocated by the application.

    By default, the young generation size is controlled by NewRatio. For example, setting -XX:NewRatio=3 means that the ratio between the young and tenured generation is 1:3. In other words, the combined size of the eden and survivor spaces will be one fourth of the total heap size.

    The parameters NewSize and MaxNewSize bound the young generation size from below and above. Setting these equal to one another fixes the young generation, just as setting -Xms and -Xmx equal fixes the total heap size. This is useful for tuning the young generation at a finer granularity than the integral multiples allowed by NewRatio.

    3.2.1 Young Generation Guarantee

    In an ideal minor collection the live objects are copied from one part of the young generation (the eden space plus the first survivor space) to another part of the young generation (the second survivor space). However, there is no guarantee that all the live objects will fit into the second survivor space. To ensure that the minor collection can complete even if all the objects are live, enough free memory must be reserved in the tenured generation to accommodate all the live objects. In the worst case, this reserved memory is equal to the size of eden plus the objects in non-empty survivor space. When there isn't enough memory available in the tenured generation for this worst case, a major collection will occur instead. This policy is fine for small applications, because the memory reserved in the tenured generation is typically only virtually committed but not actually used. But for applications needing the largest possible heap, an eden bigger than half the virtually committed size of the heap is useless: only major collections would occur. Note that the young generation guarantee applies to all of the collectors with the exception of the throughput collector . The throughput collector will proceed with a young generation collection, and if the tenured generation cannot accommodate all the promotions from the young generation, both generations are collected.

    If desired, the parameter SurvivorRatio can be used to tune the size of the survivor spaces, but this is often not as important for performance. For example, -XX:SurvivorRatio=6 sets the ratio between each survivor space and eden to be 1:6. In other words, each survivor space will be one eighth of the young generation (not one seventh, because there are two survivor spaces).

    If survivor spaces are too small, copying collection overflows directly into the tenured generation. If survivor spaces are too large, they will be uselessly empty. At each garbage collection the virtual machine chooses a threshold number of times an object can be copied before it is tenured. This threshold is chosen to keep the survivors half full. An option, -XX:+PrintTenuringDistribution, can be used to show this threshold and the ages of objects in the new generation. It is also useful for observing the lifetime distribution of an application.

    Here are the default values for the Solaris Operating Environment (SPARC Platform Edition):

    NewRatio

    2 (client JVM: 8)

    NewSize

    2228k

    MaxNewSize

    unlimited

    SurvivorRatio

    32

    The maximum size of the young generation will be calculated from the maximum size of the total heap and NewRatio. The "unlimited" default value for MaxNewSize means that the calculated value is not limited by MaxNewSize unless a value for MaxNewSize is specified on the command line.

    The rules of thumb for server applications are:

    First decide the total amount of memory you can afford to give the virtual machine. Then graph your own performance metric against young generation sizes to find the best setting.

    Unless you find problems with excessive major collection or pause times, grant plenty of memory to the young generation.

    Increasing the young generation becomes counterproductive at half the total heap or less (whenever the young generation guarantee cannot be met).

    Be sure to increase the young generation as you increase the number of processors, since allocation can be parallelized.

    4 Types of Collectors

    The discussion to this point has been about the default collector. In the J2SE platform, version 1.4.2 there are three additional collectors. Each is a generational collector which has been implemented to emphasize the throughput of the application or low garbage collection pause times.

    1. The throughput collector: this collector uses a parallel version of the young generation collector. It is used if the -XX:+UseParallelGC option is passed on the command line. The tenured generation collector is the same as the default collector.

    2. The concurrent low pause collector: this collector is used if the -XX:+UseConcMarkSweepGC is passed on the command line. The concurrent collector is used to collect the tenured generation and does most of the collection concurrently with the execution of the application. The application is paused for short periods during the collection. A parallel version of the young generation copying collector is used with the concurrent collector (i.e. if -XX:+UseConcMarkSweepGC is used on the command line then the flag UseParNewGC is also set to true if it is not otherwise explicitly set on the command line).

    3. The incremental (sometimes called train) low pause collector: this collector is used only if -Xincgc is passed on the command line. By careful bookkeeping, the incremental garbage collector collects just a portion of the tenured generation at each minor collection, trying to spread the large pause of a major collection over many minor collections. However, it is even slower than the default tenured generation collector when considering overall throughput.

    Note that -XX:+UseParallelGC should not be used with -XX:+UseConcMarkSweepGC. The argument parsing in the J2SE platform, version 1.4.2 should only allow legal combinations of command line options for garbage collectors, but earlier releases may not detect all illegal combinations and the results for illegal combinations are unpredictable.

    Always try the default collector on your application before trying one of the other collectors. Tune the heap size for your application and then consider what requirements of your application are not being met. Based on the latter, consider using one of the other collectors.

    4.1When to Use the Throughput Collector

    Use the throughput collector when you want to improve the performance of your application with larger numbers of processors. In the default collector garbage collection is done by one thread, and therefore garbage collection adds to the serial execution time of the application. The throughput collector uses multiple threads to execute a minor collection and so reduces the serial execution time of the application. A typical situation is one in which the application has a large number of threads allocating objects. In such an application it is often the case that a large young generation is needed.

    4.2 The Throughput Collector

    The throughput collector is a generational collector similar to the default collector but with multiple threads used to do the minor collection. The major collections are essentially the same as with the default collector. By default on a host with N CPUs, the throughput collector uses N garbage collector threads in the collection. The number of garbage collector threads can be controlled with a command line option (see below). On a host with 1 CPU the throughput collector will likely not perform as well as the default collector because of the additional overhead for the parallel execution (e.g., synchronization costs). On a host with 2 CPUs the throughput collector generally performs as well as the default garbage collector and a reduction in the minor garbage collector pause times can be expected on hosts with more than 2 CPUs.

    The throughput collector can be enabled by using command line flag -XX:+UseParallelGC. The number of garbage collector threads can be controlled with the ParallelGCThreads command line option (-XX:ParallelGCThreads=<desired number>). The size of the heap needed with the throughput collector to first order is the same as with the default collector. Turning on the throughput collector should just make the minor collection pauses shorter. Because there are multiple garbage collector threads participating in the minor collection there is a small possibility of fragmentation due to promotions from the young generation to the tenured generation during the collection. Each garbage collection thread reserves a part of the tenured generation for promotions and the division of the available space into these "promotion buffers" can cause a fragmentation effect. Reducing the number of garbage collector threads will reduce this fragmentation effect as will increasing the size of the tenured generation.

    4.2.1 Adaptive Sizing

    A feature available with the throughput collector in the J2SE platform, version 1.4.1 and later releases is the use of adaptive sizing (-XX:+UseAdaptiveSizePolicy), which is on by default. Adaptive sizing keeps statistics about garbage collection times, allocation rates, and the free space in the heap after a collection. These statistics are used to make decisions regarding changes to the sizes of the young generation and tenured generation so as to best fit the behavior of the application. Use the command line option -verbose:gc to see the resulting sizes of the heap.

    4.2.2 AggressiveHeap

    The -XX:+AggressiveHeap option inspects the machine resources (size of memory and number of processors) and attempts to set various parameters to be optimal for long-running, memory allocation-intensive jobs. It was originally intended for machines with large amounts of memory and a large number of CPUs, but in the J2SE platform, version 1.4.1 and later it has shown itself to be useful even on four processor machines. With this option the throughput collector (-XX:+UseParallelGC) is used along with adaptive sizing (-XX:+UseAdaptiveSizePolicy). The physical memory on the machines must be at least 256MB before AggressiveHeap can be used. The size of the initial heap is calculated based on the size of the physical memory and attempts to make maximal use of the physical memory for the heap (i.e., the algorithms attempt to use heaps nearly as large as the total physical memory).

    4.2.3 Measurements with the Throughput Collector

    The verbose garbage collector output is the same for the throughput collector as with the default collector.

    4.3 When to Use the Concurrent Low Pause Collector

    Use the concurrent low pause collector if your application would benefit from shorter garbage collector pauses and can afford to share processor resources with the garbage collector when the application is running. Typically applications which have a relatively large set of long-lived data (a large tenured generation), and run on machines with two or more processors tend to benefit from the use of this collector. However, this collector should be considered for any application with a low pause time requirement. Optimal results have been observed for interactive applications with tenured generations of a modest size on a single processor.

    4.4 The Concurrent Low Pause Collector

    The concurrent low pause collector is a generational collector similar to the default collector. The tenured generation is collected concurrently with this collector.

    This collector attempts to reduce the pause times needed to collect the tenured generation. It uses a separate garbage collector thread to do parts of the major collection concurrently with the applications threads. The concurrent collector is enabled with the command line option -XX:+UseConcMarkSweepGC. For each major collection the concurrent collector will pause all the application threads for a brief period at the beginning of the collection and toward the middle of the collection. The second pause tends to be the longer of the two pauses and multiple threads are used to do the collection work during that pause. The remainder of the collection is done with a garbage collector thread that runs concurrently with the application. The minor collections are done in a manner similar to the default collector although multiple garbage collector threads are used to reduce the minor collection times. See "Parallel Minor Collection Options with the Concurrent Collector" below for information on using multiple threads with the concurrent low pause collector.

    The techniques used in the concurrent collector (for the collection of the tenured generation) are described at:

    http://research.sun.com/techrep/2000/abstract-88.html

    4.4.1 Overhead of Concurrency

    The concurrent collector trades processor resources (which would otherwise be available to the application) for shorter major collection pause times. The concurrent part of the collection is done by a single garbage collection thread. On an N processor system when the concurrent part of the collection is running, it will be using 1/Nth of the available processor power. On a uniprocessor machine it would be fortuitous if it provided any advantage. It conceivably could break up a single long pause into several shorter pauses (a pause being defined in this case as the absence of any application threads running) but that is not the intent of the concurrent collector. The concurrent collector also has some additional overhead costs that will take away from the throughput of the applications, and some inherent disadvantages (e.g., fragmentation) for some types of applications. On a two processor machine there is a processor available for applications threads while the concurrent part of the collection is running, so running the concurrent garbage collector thread does not "pause" the application. There may be reduced pause times as intended for the concurrent collector but again less processor resources are available to the application and some slowdown of the application should be expected. As N increases, the reduction in processor resources due to the running of the concurrent garbage collector thread becomes less, and the advantages of the concurrent collector become more.

    4.4.2 Young Generation Guarantee

    As with the default collector a minor collection may require enough space in the tenured generation to accommodate all the objects in eden and one survivor space. Because fragmentation can occur in a concurrent collection, the requirement for this guarantee is more severe with the concurrent collector. There has to be enough contiguous space available in the tenured generation for all the objects in eden and one survivor space because there is no a priori way (except at a significant performance cost) to know the distribution of the sizes in eden and the one survivor space. A larger heap is almost always needed when the concurrent collector is used as compared to the default collector. As with the default collector the space in the tenured generation must be reserved but does not actually have to be used. As a rough estimate choose the appropriate young generation and tenured generation heap sizes as would be appropriate for the default collector, and then increase the tenured generation size by the equivalent of the young generation size for the concurrent collector. This is a very rough approximation and the correct values are application dependent.

    4.4.3 Full Collections

    The concurrent collector uses a single garbage collector thread that runs simultaneously with the application threads with the goal of completing the collection of the tenured generation before it becomes full. In normal operation, the concurrent collector is able to do most of its work with the application threads still running, so only brief pauses are seen by the application threads. As a fall back, if the concurrent collector is unable to finish before the tenured generation fills up, the application is paused and the collection is completed with all the application threads stopped. Such collections with the application stopped are referred to as full collections and are a sign that some adjustments need to be made to the concurrent collection parameters.

    4.4.4 Floating Garbage

    A garbage collector works to find the live objects in the heap. Because application threads and the garbage collector thread run concurrently, objects that are found to be alive by the garbage collector thread may become dead by the time collection finishes. Such objects are referred to as floating garbage. The amount of floating garbage depends on the length of the concurrent collection (more time for the applications threads to discard an object) and on the particulars of the application. As a rough rule of thumb try increasing the size of the tenured generation by 20% to account for the floating garbage. Floating garbage is collected at the next garbage collection.

    4.4.5 Pauses

    The concurrent collector pauses an application twice during a concurrent collection cycle. The first pause is to mark as live the objects directly reachable from the roots (e.g., objects on thread stack, static objects and so on) and elsewhere in the heap (e.g., the young generation). This first pause is referred to as the initial mark. The second pause comes at the end of the marking phase and finds objects that were missed during the concurrent marking phase due to the concurrent execution of the application threads. The second pause is referred to as the remark.

    4.4.6 Concurrent Phases

    The concurrent marking occurs between the initial mark and the remark. During the concurrent marking the concurrent garbage collector thread is executing and using processor resources that would otherwise be available to the application. After the remark there is a concurrent sweeping phase which collects the dead objects. During this phase the concurrent garbage collector thread is again taking processor resources from the application. After the sweeping phase the concurrent collector sleeps until the start of the next major collection.

    4.4.7 Measurements with the Concurrent Collector

    Below is output for -verbose:gc with -XX:+PrintGCDetails (some details have been removed). Note that the output for the concurrent collector is interspersed with the output from the minor collections. Typically many minor collections will occur during a concurrent collection cycle. The CMS-initial-mark: indicates the start of the concurrent collection cycle. The CMS-concurrent-mark: indicates the end of the concurrent marking phase as CMS-concurrent-sweep: marks the end of the concurrent sweeping phase. Not discussed before is the precleaning phase indicated by CMS-concurrent-preclean: which represents work that can be done concurrently and is in preparation for the remark phase CMS-remark. The final phase is indicated by the CMS-concurrent-reset: and is in preparation for the next concurrent collection.

    [GC [1 CMS-initial-mark: 13991K(20288K)] 14103K(22400K), 0.0023781 secs]

    [GC [DefNew: 2112K->64K(2112K), 0.0837052 secs] 16103K->15476K(22400K), 0.0838519 secs]

    ...

    [GC [DefNew: 2077K->63K(2112K), 0.0126205 secs] 17552K->15855K(22400K), 0.0127482 secs]

    [CMS-concurrent-mark: 0.267/0.374 secs]

    [GC [DefNew: 2111K->64K(2112K), 0.0190851 secs] 17903K->16154K(22400K), 0.0191903 secs]

    [CMS-concurrent-preclean: 0.044/0.064 secs]

    [GC[1 CMS-remark: 16090K(20288K)] 17242K(22400K), 0.0210460 secs]

    [GC [DefNew: 2112K->63K(2112K), 0.0716116 secs] 18177K->17382K(22400K), 0.0718204 secs]

    [GC [DefNew: 2111K->63K(2112K), 0.0830392 secs] 19363K->18757K(22400K), 0.0832943 secs]

    ...

    [GC [DefNew: 2111K->0K(2112K), 0.0035190 secs] 17527K->15479K(22400K), 0.0036052 secs]

    [CMS-concurrent-sweep: 0.291/0.662 secs]

    [GC [DefNew: 2048K->0K(2112K), 0.0013347 secs] 17527K->15479K(27912K), 0.0014231 secs]

    [CMS-concurrent-reset: 0.016/0.016 secs]

    [GC [DefNew: 2048K->1K(2112K), 0.0013936 secs] 17527K->15479K(27912K), 0.0014814 secs]

    The initial mark pause is typically short relative to the minor collection pause time. The times of the concurrent phases (concurrent mark, concurrent precleaning, and concurrent sweep) may be relatively long (as in the example above) when compared to a minor collection pause but the application is not paused during the concurrent phases. The remark pause is affected by the specifics of the application (e.g., a higher rate of modifying objects can increase this pause) and the time since the last minor collection (i.e., more objects in the young generation may increase this pause).

    4.4.8 Parallel Minor Collection Options with the Concurrent Collector

    On a multiple processor platform, the default for the UseParNewGC option is true.

    If the UseParNewGC option is in use the remark pauses may be decreased with the CMSParallelRemarkEnabled option.

    -XX:+CMSParallelRemarkEnabled

    4.5 When to Use the Incremental Low Pause Collector

    Use the incremental low pause collector when your application can afford to trade longer and more frequent young generation garbage collection pauses for shorter tenured generation pauses. A typical situation is one in which a larger tenured generation is required (lots of long-lived objects), a smaller young generation will suffice (most objects are short-lived and don't survive the young generation collection), and only a single processor is available.

    4.6 The Incremental Low Pause Collector

    The incremental low pause collector is a generational collector similar to the default collector. The minor collections are done with the same young generation collector as the default collector. Do not use either -XX:+UseParallelGC or -XX:+UseParNewGC with this collector. The major collections are done incrementally on the tenured generation.

    This collector (also known as the train collector) collects portions of the tenured generation at each minor collection. The goal of the incremental collector is to avoid very long major collection pauses by doing portions of the major collection work at each minor collection. The incremental collector will sometimes find that a non-incremental major collection (as is done in the default collector) is required in order to avoid running out of memory.

    This collector can cause some fragmentation of the heap, so sometimes a larger tenured generation heap size will be required, as compared to the default mark-sweep-compact collector.

    In order to collect a portion of the tenured generation at each minor collection additional information is maintained by the incremental collector. The overhead of maintaining this information increases the overall cost of garbage collection and throughput is typically less than when using the default mark sweep collector.

    The incremental collector should be used by first trying the default collector and sizing the heap as discussed for the default collector. If the major pauses cannot be reduced to an acceptable level by adjusting the sizes of the generations in the heap, try the incremental collector with the same generation sizes first. Then vary the generation sizes to fit your application.

    • If full collections are occurring, the incremental collector may not be able to incrementally collect the tenured generation fast enough to finish before the tenured generation runs out of memory. Try decreasing the size of the young generation in order to increase the number of young generation collections

    • If full collections are occurring because the young generation guarantee cannot be met, then fragmentation may be the cause. The failure to guarantee a young generation collection is indicated by a young generation collection that does not recover any space (see the example below). Increase the size of the tenured generation to offset the fragmentation. The space in the larger generation may not be used but it will be available for the young generation guarantee.

    4.6.1 Measurements with the Incremental Collector

    For details on the incremental collector in addition to the -verbose:gc command line flag, add the flag -XX:+PrintGCDetails (which first became available in the J2SE platform, version 1.4.1). A typical line of output with the details flag will look like this.

    [GC [DefNew: 2074K->25K(2112K), 0.0050065 secs][Train: 1676K->1633K(63424K), 0.0082112 secs] 3750K->1659K(65536K), 0.0138017 secs]

    This line says that a young generation collection was done and took about 5 milliseconds. An incremental collection was done (indicated by the Train: part of the line) and took about 8 milliseconds. If a full collection is done instead of an incremental collection, the line will include Train MSC: which indicates a full (mark-sweep-compact) collection was done.

    [GC [DefNew: 2049K->2049K(2112K), 0.0003304 secs][Train MSC: 61809K->357K(63424K), 0.3956982 secs] 63859K->394K(65536K), 0.3987650 secs]

    Also in this line you can see that the minor collection was not effective. Before the collection 2049KB of space in the young generation was occupied and after the collection the same amount was occupied. This indicates that the contiguous free space in the tenured generation was not enough to satisfy the young generation guarantee.

    5 Other Considerations

    For most applications the permanent generation is not relevant to garbage collector performance. However, some applications dynamically generate and load many classes. For instance, some implementations of JSPTM pages do this. If necessary, the maximum permanent generation size can be increased with MaxPermSize.

    Some applications interact with garbage collection by using finalization and weak/soft/phantom references. These features can create performance artifacts at the Java programming language level. An example of this is relying on finalization to close file descriptors, which makes an external resource (descriptors) dependent on garbage collection promptness. Relying on garbage collection to manage resources other than memory is almost always a bad idea.

    Another way applications can interact with garbage collection is by invoking full garbage collections explicitly, such as through the System.gc() call. These calls force major collection, and inhibit scalability on large systems. The performance impact of explicit garbage collections can be measured by disabling explicit garbage collections using the flag -XX:+DisableExplicitGC.

    One of the most commonly encountered uses of explicit garbage collection occurs with RMI's distributed garbage collection (DGC). Applications using RMI refer to objects in other virtual machines. Garbage can't be collected in these distributed applications without occasional local collection, so RMI forces periodic full collection. The frequency of these collections can be controlled with properties. For example,

    java -Dsun.rmi.dgc.client.gcInterval=3600000
    -Dsun.rmi.dgc.server.gcInterval=3600000 ...

    specifies explicit collection once per hour instead of the default rate of once per minute. However, this may also cause some objects to take much longer to be reclaimed. These properties can be set as high as Long.MAX_VALUE to make the time between explicit collections effectively infinite, if there is no desire for an upper bound on the timeliness of DGC activity.

    The Solaris 8 Operating Environment supports an alternate version of libthread that binds threads to light-weight processes (LWPs) directly. Some applications can benefit greatly from the use of the alternate libthread. This is a potential benefit for any threaded application. To try this, set the environment variable LD_LIBRARY_PATH to include /usr/lib/lwp before launching the virtual machine. The alternate libthread is the default libthread in the Solaris 9 Operating Environment.

    Soft references are cleared less aggressively in the server virtual machine than the client. The rate of clearing can be slowed by increasing a parameter in this way: -XX:SoftRefLRUPolicyMSPerMB=10000. The default value is 1000, or one second per megabyte.

    6 Conclusion

    Garbage collection can become a bottleneck in different applications depending on the requirements of the applications. By understanding the requirements of the application and the garbage collection options, it is possible to minimize the impact of garbage collection.

    7 Other Documentation

    7.1 Example of Output

    The GC output examples document contains examples for different types of garbage collector behavior. The examples show the diagnostic output from the garbage collector and explain how to recognize various problems. Examples from different collectors are included.

    7.2 Frequently Asked Questions

    A FAQ is included that contains answers to specific questions. The level of detail in the FAQ is generally greater than in this tuning document.

    February 01

    小学生的想象力

    要求:把以下四句话用关联词连接
      1.李姐姐瘫痪了;
      2.李姐姐顽强地学习;
      3.李姐姐学会了多门外语;
      4.李姐姐学会了针灸。
      (注:正确答案应该是:李姐姐虽然瘫痪了,但顽强地学习,不仅学会了多门外语,而且还学会了针灸。)
      结果有一个孩子写:虽然李姐姐顽强地学会了针灸和多门外语,可她还是瘫痪了。

      后来,发现更猛的孩子写道:
    李姐姐不但学会了外语,还会了针灸,她那么顽强地学习,终于瘫痪了。
      李姐姐之所以瘫痪了,是因为顽强地学习,非但学会了多门外语,甚至学会了针灸。
      李姐姐是那么顽强的学习,不但学会了多门外语和针灸,最后还学会了瘫痪。
      李姐姐学会了多门外语,学会了针灸,又在顽强的学习瘫痪。
      李姐姐通过顽强的学习,学会了多门外语和针灸,结果照着一本外文版针灸书把自己扎瘫痪了。

    October 28

    Part II: How to use JConsole

    接着前一篇Blog,现在JConsole已经可以启动了。而且JMX的配置方面也整理了一下。JConsole的具体使用界面上,有以下这样的一些截图:

    连接上远端的JVM以后可以通过JConsole看到如下截图:

     

    图1:“概述”界面

     

    图2:“内存”界面

     

    图3:“线程”界面

     

    图4:“类”界面

     

    图5:“VM 摘要”界面

     

    图6:“MBean”界面

    前面的5个标签页,主要通过图表的方式,将JVM的运行状况用图表的方式表示出来,可以看到内存,CPU,线程,类的概况,以及各个方面的详细图表情况,这样的图表方式可以非常方便的看到系统运行时的压力以及瓶颈在哪里。

    第六张标签页显示了MBean的情况,MBean是JMX体系下的一种JavaBean,可以通过MBean所提供的方法,获取某个具体对象的运行情况,甚至可以得到一些对象的Dump数据。MBean非常的多,使用方法也比较麻烦,具体请参看下面的文章:Overview of Monitoring and Management.

    http://www.totodotnet.net/2007/08/10/part-ii-how-to-use-jconsole/

    Part I: How to use JConsole

    JConsole是一个JDK中提供的JVM监视与管理的工具,主要是通过JMX来提供监视与管理。

    默认情况下,JVM是不启动JMX服务,并提供被监视与被管理的能力的,必须在启动Java程序之前,在Java [opt] [app]中指定JMX的服务。JConsole提供本地和远程的两种监管方式,远程又可以分为直接监视,另外一种是通过JMX的服务器来管理。

    根据目前我的需要,我举一个很简单的远程监管例子。因为JConsole本身也要耗费一定的资源,所以用远程方式是比较推荐的。

    首先启动JConsole:

     

    (因为在日文系统中,所以显示的为日文)

    选择下面的Remote Access,输入host:portNumb的格式,另外输入用户名和密码,用户名和密码存储在<JAVA_HOME>/lib/management目录下,将jmxremote.password.template 复制为management.jmxremote.password(如果需要可以将文件的只读属性打开)。注意:这个文件是放在JRE的lib目录下。修改过以后的内容大致如下:

    ######################################
    # File permissions of the jmxremote.password file
    ######################################
    # …

    monitorRole 333
    controlRole 333

    另外,默认情况下,SSL是被打开的,需要在被监视的机器上生成相应的SSL证书。在Java中可以使用keytool来生成,具体步骤如下:

    • 在命令行输入 keytool -genkey
    • 其次输入 keytool -certreq 来生成一个签名过的证书
    • 将证书导入 keytool -import
      1. KeyTool具体的用法参考下面两个链接: (Solaris and Linux) (Windows).
      2. 以上第一个命令会产生一个.keystore的文件,保存在c:\documents and setting\<username>\.keystore

    其中第三条将需要你将第二步生成的CSR文件提交给VeriSign这样公司验证,然后返回给你一个可以使用CER证书,然后在Import,我们主要目的是为了体验JConsole,所以这一步我们就略过。所以我们设定不使用SSL,具体设置如下:

    -Dcom.sun.management.jmxremote.authenticate=false
    -Dcom.sun.management.jmxremote.ssl=false

    注意:这两行将使用非认证,非SSL的情况,在真实的服务器上要小心,很容易留下漏洞的。

    在Windows系统下,如果你将Tomcat安装为服务模式,则可以在右下角Tray 图标中点击配置Tomcat,可以在例如下图的属性中配置,非常的简单:

     

    如果不使用Windows系统,则需要在Catalina.bat中改写Java运行的参数。

    改完了Tomcat的配置,启动Tomcat。

    在远程机器上点击JConsole的连接即可。JConsole的具体使用以及分析下次继续。

    ——————————————————-
    JMX 的配置主要在Java程序启动的时候使用,这里重新整理了一下,更加清晰易懂一些:

    方法1: 最简单的方式:不用密码,不用SSL

    -Dcom.sun.management.jmxremote.authenticate=false
    -Dcom.sun.management.jmxremote.ssl=false
    -Dcom.sun.management.jmxremote.port=<define a random port>

    方法2: 使用密码,不用SSL

    -Dcom.sun.management.jmxremote.authenticate=true
    -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password
    -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access

    $CATALINA_BASE/conf/目录下添加jmxremote.password文件,并添加下面两行:

    monitorRole <Your password>
    controlRole <Your password>

    $CATALINA_BASE/conf/目录下添加jmxremote.access文件,并添加下面两行:

    monitorRole readOnly
    controlRole readWrite

    这两种方法是最简单的,并且第二种方法具有一定的安全性。具体可以参考Tomcat的文档:Monitoring

    http://www.totodotnet.net/2007/08/09/part-i-how-to-use-jconsole/

    OutOfMemory:PermGen Space异常的处理和分析

    Java程序员没有遇到过OutOfMemory简直就是不可能的事情!

    可见在Java的世界中,太多的不确定因素导致Java运行程序直接崩溃,直接抛出OutOfMemory异常,而一旦遇到了这个问题,调查起来就非常的困难。在JDK 5.0以前,OutOfMemory只有这么一句话: java.lang.OutOfMemory Exception…基本上无从下手,无从分析。从JDK 5.0以后对OutOfMemory增加了许多的详细说明,为这个异常的分析提供了很大的便利。

    这次遇到的问题就是会抛出OutOfMemory:PermGen Space的异常,这个异常非常有意思,根据【此文章】的描述,这是一个Sun JVM的bug,从2003年开始,一只到现在都没有解决。而且提出来的解决方案是使用JRockit。Bug产生的原因已经找到,就是因为JVM在分配PermGen Space的时候出现了PermGen Space不足的情况,默认情况下 PermGen的大小为64M,在不换用JRockit的情况下,可以在启动JVM的时候添加一个参数: -XX: MaxPermSize= 128m| 256m| 512m。

    那么究竟什么是PermGen呢?

    PermGen 原来是指Permanent Generation,本身是在Java的垃圾收集机制(GC)中产生的一个概念。Java的垃圾收集机制最早只是遍历所有的对象,如果发现某个对象没有被引用,则回收,这是在早期的Java 1.0和Java 1.1的时候的GC规则。慢慢的,这样一种“愚蠢的”GC算法成为了JVM性能的瓶颈,在拥有大量数据的Java应用程序中,GC的算法被高度强化,于是各种各样高效的JVM GC算法被发展了起来。从J2SE也就是Java 1.2开始,JVM引入了多种GC算法,其中一种用的非常多的就是Generational Collection,中文也叫做“分代收集法”。

    分代收集法摈弃了对所有对象的遍历,而是采用一些经验属性去避免额外的工作(While naive garbage collection examines every live object in the heap, generational collection exploits several empirically observed properties of most applications to avoid extra work)。其中导入了一个非常关键的概念:infant mortality (幼儿死亡率),这表示越是新生成的变量或者对象,越容易被收集。下面一张图表示了对象的生命周期,横轴表示的是测试到对象的生命周期,纵轴表示在一个指定的生命周期上被回收的对象数量。

    Histogram of lifetime 

    可以看到,在使用了分代收集法以后,年轻一代的对象被收集的比例最高。并且在内存中的对象会按照不同的“年龄”来划分,当一个年龄段的对象满了以后,在这个年龄段上就会发生垃圾收集,从最年轻的一代开始,一直到“永生代”,在内存中,所有的对象可以划分为很多代,最后的一代“永生代”就是“Permanent Generation”,这里就是直接引出“Permanent Generation”概念的地方。具体可以参考下图:

     

    根据前面所说的情况,在分代垃圾收集的情况下会产生Permanent Generation的概念,而这个分代垃圾收集法是并行收集和并发收集的基础,所以Permanent Generation会一直存在,那么这个Permanent Generation究竟是做什么用的呢?这里保存了JVM中所有对象的类信息,包括类的元数据,还有方法描述等等,所以这一代内存垃圾收集算法是不一样的,在Java大程序的情况下,尤其是J2EE 或者说Java EE的大型应用程序上,Permanent Generation的大小会直接限定能载入类的数量和大小。

    【解决办法】就是设定JVM启动的时候参数,可以如下设置:

    java -XX: PermSize=64m -XX: MaxPermSize=128m

    另外PermSize 和MaxPermSize如果设置为相同还可以在一定程度上提高性能,因为,PermSize在不断的变化中会需要转移其中的数据。如果固定了以后,则可以减少每次扩大PermSize带来的性能损失。

    更多的请参考 【Java官方站点】

    另外,还可以在Java启动的时候添加下面的参数来看GC的运行情况:

    Java -verbosegc

    (完)

    http://www.totodotnet.net/2007/08/15/outofmemory%ef%bc%9apermgen-space%e5%bc%82%e5%b8%b8%e7%9a%84%e5%a4%84%e7%90%86%e5%92%8c%e5%88%86%e6%9e%90/

    October 14

    关掉自动更新重启提示(XP)

    Windows自动更新在完成后会不停的弹出需要重启的窗口,一不小心就会按错。

    关掉这个讨厌的提示,而且不影响自动更新正常运行只需:开始运行sc stop wuauserv

    另一个方法是:开始运行gpedit.msc计算机配置>管理模板>windows 组件>windows update>重新提示计划安装后的重新启动。选择启用,设置一个很长的时间。

    来自LifeHack

    August 15

    ASM 2.0 Bytecode Framework入门

    编写者:Eugene Kuleshov
    翻译者:cleverpig
    08/17/2005

    Java提供的动态类装载和反射使其成为了动态语言。但是在一些情况下,反射操作并没有多大意义,开发者需要从非Java源代码中生成bytecode,例如像Groovy(JSR-241)或者BeanShell(JSR-274)这样的脚本语言,或者从例如关系映射配置(OR-mapping configuration)这样的元数据(metadata)中生成bytecode。在和现存的类一起使用时,尤其是在源代码没有Java源代码的情况下,有些工具需要对相互依赖性或者方法进行静态分析、或者为了生成测试评估、检测bug和反模式。对于在Java5中新增加的特性,例如 annotation(注释)和generic(类属),它们都将影响bytecode的结构,并且也是那些用来保持bytecode良好的性能的 bytecode操作工具所应该特别关注的。本文将给出一个用于Java的、最小、最快的bytecode操作框架。

    框架结构

    ASM bytecode操作框架使用Java语言编写并采用了基于访问者(visitor-based)的方式来生成bytecode、驱动现有类的变化。它使开发者能够避免直接处理类实例池和在方法bytecode中的位移,因此它为开发者隐藏掉了bytecode的复杂性并且提供了与其它工具(例如 BCEL, SERP, 或者 Javassist)相比更佳的性能。

    为了提供灵活的捆绑,ASM被分割为以下几个package:

    Arrangement of ASM packages
    图1 ASM的package分布

    • Core package提供了一个读写、修改Java bytecode的API,并且为其它的package定义了依据。这个package对于生成Java bytecode、实现大多数的bytecode变换而言意义重大。
    • Tree package提供了Java bytecode的内存表示法。
    • Analysis package提供了基本的数据流分析和类型检查算法,它们将用于在tree oackage中存储Java方法bytecode。
    • Commons package(包含在ASM2.0中)提供了一些常用的bytecode转换和用于简化bytecode生成的适配器。
    • Util package包含了一些帮助类和简单的bytecode验证器,它们将有助于开发或者测试。
    • XML package提供了一个用于在bytecode和XML之间进行转换的适配器,和一些允许使用XSLT定义bytecode转换的兼容SAX的适配器。

    下面的一些章节将对ASM框架中的Core package进行介绍。为了更好地了解这个package的组织方式,你需要对定义在 JVM规范中的bytecode结构做一些基本的了解。这里提供了一个高层面的类文件格式图表([*]表示可重复结构)。

    
        
      [1]-------------------------------------------+
    | Header and Constant Stack |
    +--------------------------------------------+
    | [*] Class Attributes |
    [2]------------+------------------------------+
    | [*] Fields | Field Name, Descriptor, etc |
    | +------------------------------+
    | | [*] Field Attributes |
    [3]------------+------------------------------+
    | [*] Methods | Method Name, Descriptor, etc |
    | +------------------------------|
    | | Method max stack and locals |
    | |------------------------------|
    | | [*] Method Code table |
    | |------------------------------|
    | | [*] Method Exception table |
    | |------------------------------|
    | | [*] Method Code Attributes |
    | +------------------------------|
    | | [*] Method Attributes |
    +-------------+------------------------------+

    这里我们需要注意以下几点:

    • 所有的描述符、字符串和其它用在类结构中的常量都被存放在类文件开头的常量堆栈中(Constant Stack) ,并通过其索引被其它结构引用。
    • 每个类都必须具有头(包括类名、父类、接口等)和常量堆栈。而其它成员(例如类字段列表、类方法列表及属性)都是可选的(可提供、也可不提供)。
    • 每个字段部分都包括了例如名称、访问标志(public, private等)、描述符和字段属性这些字段信息。
    • 每个方法部分包含了相同的头信息和关于最大堆栈、最大本地变量个数的信息,这些信息用来验证bytecode。对于非抽象、非本地的方法 ,这里提供了一个方法命令表(方法体),一个异常表。除了这些,它还能提供其它的方法属性。
    • 每个类、字段、方法和方法代码的属性都有其自己的名字,这些都在类JVM规范中文件格式有所说明。它们代表了例如源文件名、内部类、签名、行号、本地变量表和注释等关于bytecode信息的属性。JVM规范允许包含附加信息的自定义属性,而这些自定义属性将被标准的虚拟机忽略掉。请注意,Java5注释实际上淘汰了自定义属性,因为标注语法允许你更好地表示任何东西。
    • 方法代码表包含了一个用于Java虚拟机的命令列表。其中的一些(例如异常、行号、本地变量表)在代码表中使用位移表示,而当从方法代码表中插入、移除命令时这些位移值可能需要修正。

    正如你所见,对bytecode进行优化并非易事。而ASM框架降低了下层结构的复杂性并为访问bytecode信息进行复杂的变换提供了简化API。

    基于事件的bytecode处理

    Core package使用一种推送的方式(与常用在 SAX API中的“Visitor”设计模式相似)来遍历复杂的bytecode结构。ASM定义了许多接口:例如ClassVisitor (在上面的类文件格式图表中的第一块), FieldVisitor (第二块), MethodVisitor(第三块)和AnnotationVisitor. AnnotationVisitor这个特殊的接口,它能够表达分层次的注释结构。在下面的一些章节将展示这些接口相互之间如何交换和如何一起被用于实现bytecode变换以及如何从bytecode中捕获信息的。

    Core package能够被逻辑划分为以下两部分:

    • bytecode生产者,例如ClassReader或者一种能够进行对visitor类上的方法进行一系列调用的自定义类。
    • bytecode消费者,例如(ClassWriter, FieldWriter, MethodWriterAnnotationWriter),适配器(ClassAdapterMethodAdapter)或者其它实现visitor接口的类。

    图-2展示了常见的生产者-消费者交互顺序图表

    Sequence diagram for producer-consumer interaction
    图-2 生产者-消费者交互顺序图表

    在上面的交互中,客户端应用创建ClassReader并通过将一个具体的ClassVisitor示例作为参数调用accept()方法。然后ClassReader解析这个类,并针对每个bytecode结构块调用ClassVisitor的触发“visit”事件。对于重复的上下文(例如字段、方法、注释)来讲, ClassVisitor能够创建继承自相应的接口(FieldVisitor, MethodVisitor, 或者 AnnotationVisitor)的子访问者,并将它们返回给生产者。当生产者接收到来自FieldVisitor 或者 MethodVisitor 的null值时,它将跳过这部分(尤其是在此情况下,ClassReader不能解析相应的bytecode,这将可能导致一些由访问者驱使的“lazy loading”)。否则,相应的子上下文事件将被委派给子访问者实例。在每个子上下文结束时,生产者都将调用 visitEnd()方法并将移动到下一个部分(下一个字段、方法等)。

    bytecode消费者将在一个“责任链”模式中被链接在一起:通过人工将事件委派给链中的下一个访问者、或者使用继承自 ClassAdapter或者 MethodAdapter的访问者(ClassAdapter或者 MethodAdapter将所有的访问方法都委派给了它们)。那些委派者从一方面讲就像bytecode消费者,而从另一方面看它们还是bytecode消费者。为了实现特殊的bytecode变换,它们能够修改这些天然的委派:

    • 为了去除类的字段、方法、方法命令等而忽略访问调用委派。
    • 为了重命名类、方法、类型等而修改访问调用参数。
    • 为了引入新的字段或者方法、为现有方法注入新的代码而增加新的访问调用。

    这个责任链能够被ClassWriter这个访问者终止,后者将生成最终的bytecode。例如:

    
      ClassWriter cw = new ClassWriter(computeMax);
      ClassVisitor cc = new CheckClassAdapter(cw);
      ClassVisitor tv =
        new TraceClassVisitor(cc, new PrintWriter(System.out));
      ClassVisitor cv = new TransformingClassAdapter(tv);
      ClassReader cr = new ClassReader(bytecode);
      cr.accept(cv, skipDebug);
      byte[] newBytecode = cw.toByteArray();
    
    

    在上面的代码中,TransformingClassAdapter实现了自定义类变换并将结果作为构造函数的参数发送给TraceClassVisitorTraceClassVisitor将打印完成变换后的类并委派相同的事件给CheckClassAdapter,后者将在完成简单的bytecode验证后将事件传送给ClassWriter

    大多数访问方法都接受例如intbooleanString 这些简单的参数。在具有引用了bytecode中常量的字符串参数的访问方法中,ASM使用和在JVM中相同的表示法。例如,所有的类名(例如父类、接口、异常、字段所属类、在方法代码中引用的方法)都应该以内部形式描述。字段和方法描述符(通常为desc参数)也应该在JVM规范中找到。对于用于表示类属信息的signature参数也使用同样的方法,因此它们应该遵守在经过修订的类文件格式的4.4.4节中的语法定义。这种方式将有助于在无需变换时避免没有必要的计算。为了有助于构造和解析这些描述符,Type类提供了一些静态方法:

    • String getMethodDescriptor(Type returnType, Type[] argumentTypes)
    • String getInternalName(Class c)
    • String getDescriptor(Class c)
    • String getMethodDescriptor(Method m)
    • Type getType(String typeDescriptor)
    • Type getType(Class c)
    • Type getReturnType(String methodDescriptor)
    • Type getReturnType(Method m)
    • Type[] getArgumentTypes(String methodDescriptor)
    • Type[] getArgumentTypes(Method m)

    请注意这些描述副正在使用一种“被擦除”的表示法,因为其中并不包括类属的信息。类属信息实际保存在一个分离的bytecode属性中,但ASM处理了这个属性并将类属签名字符串传入到相应访问方法中的一个signature参数中。signature字符串的值也使用JVM表示法,它是从Java代码中的类属声明中唯一的映射,但这也为那些需要从类属中接收细节信息的工具带来了挑战。为了处理signature,ASM提供了SignatureVisitor, SignatureReaderSignatureWriter类,它们使用和其它ASM访问者相同的方式工作:

    Sequence diagram for Signature classes
    图-3. Signature类顺序图表

    Util package包含了TraceSignatureVisitor,它实现了SignatureVisitor,并使我们能够将一个signature值转换为一个带有类属的Java声明。下面就是一个将方法签名转换为Java方法声明的示例。

      TraceSignatureVisitor v =
    new TraceSignatureVisitor(access);
    SignatureReader r = new SignatureReader(sign);
    r.accept(v);
    String genericDecl = v.getDeclaration();
    String genericReturn = v.getReturnType();
    String genericExceptions = v.getExceptions();

    String methodDecl = genericReturn + " " +
    methodName + genericDecl;
    if(genericExceptions!=null) {
    methodDecl += " throws " + genericExceptions;
    }

    截止到上面,我们已经谈了ASM框架的通用设计和对类结构的操作。但是最有趣的部分是ASM如何处理方法代码。

    访问方法代码

    在ASM中,每个方法声明都通过ClassVisitor.visitMethod()方法表示,而方法bytecode的剩余部分(见类文件格式图表中的第三部分)则通过MethodVisitor类的一些visit方法来表示。这些方法按照下面的顺序被调用,其中“*”表示重复的方法,而“?”则表示至少被调用一次的方法。另外,visit...InsnvisitLabel方法必须按照被访问代码中的bytecode命令顺序来调用,visitTryCatchBlockvisitLocalVariablevisitLineNumber则必须在作为参数传入的标签被访问后才能被调用。

    ?

    visitAnnotationDefault

    Visits the default value for annotation interface method

    *

    visitAnnotation

    Visits a method annotation

    *

    visitParameterAnnotation

    Visits a method parameter annotation

    *

    visitAttribute

    Visits a non-standard method attribute

    ?

    visitCode

    Starts the visit of the method's code for non-abstract and non-native methods

    *
    visitInsn
    Visits a zero operand instruction: NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.

    visitFieldInsn
    Visits a field instruction: GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.

    visitIntInsn
    Visits an instruction with a single int operand: BIPUSH, SIPUSH, or NEWARRAY.

    visitJumpInsn
    Visits a jump instruction: IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL, or IFNONNULL.

    visitTypeInsn
    Visits a type instruction: NEW, ANEWARRAY, CHECKCAST, or INSTANCEOF.

    visitVarInsn
    Visits a local variable instruction: ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE, or RET.

    visitMethodInsn
    Visits a method instruction: INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, or INVOKEINTERFACE.

    visitIincInsn
    Visits an IINC instruction.

    visitLdcInsn
    Visits an LDC instruction.

    visitMultiANewArrayInsn
    Visits a MULTIANEWARRAY instruction.

    visitLookupSwitchInsn
    Visits a LOOKUPSWITCH instruction.

    visitTableSwitchInsn
    Visits a TABLESWITCH instruction.

    visitLabel
    Visits a label.

    visitLocalVariable
    Visits a local variable declaration.

    visitLineNumber
    Visits a line number declaration.

    visitTryCatchBlock
    Visits a try-catch block.

    visitMaxs
    Visits the maximum stack size and the maximum number of local variables of the method.

    visitEnd
    Visits the end of the method.

    值得注意的是visitEnd方法必须在方法处理结束时被调用。ClassReader将完成这项任务,但它也要小心自定义bytecode生产者:例如从草草编写后生成的类或是在引入新方法时。

    还需要注意的是如果一个方法实际上具有一些bytecode(例如它不是抽象的或者本地的方法),那么visitCode将必须在第一次visit...Insn调用之前被调用,visitMaxs方法则必须在最后一次visit...Insn调用之后被调用。

    每个visitIincInsnvisitLdcInsnvisitMultiANewArrayInsn、visitLookupSwitchInsnvisitTableSwitchInsn方法唯一地表示了一种bytecode命令。其余的visit...Insn方法根据其名称有所区分——visitInsn, visitFieldInsn, visitIntInsn, visitJumpInsn, visitTypeInsn, visitVarInsnvisitMethodInsn代表了一种以上的bytecode命令,它们的操作代码作为方法的第一个参数被传入。这些操作代码的常量定义在Opcodes接口中。这种方式对于bytecode解析和格式化来讲是非常需要的。但由于ClassWriter并不验证这些约束,因此这对于尝试生成代码的开发者来讲的确是一种挑战。但是,ASM也提供了一个CheckClassAdapter来用于在开发过程中测试生成的代码。

    另外一个对于任何一种bytecode生成物或者变化产物的挑战是在方法代码中的位移将会发生改变,因此在附加指令插入后或者从方法代码中删除指令时要修正位移值。这应用于所以跳转操作代码(if, goto, jsr, and switch)、try-catch块、行号和本地变量声明、一些特殊属性(例如在CLDC中使用的StackMap)。但,ASM为开发者隐藏了这种复杂性。为了描述在方法bytecode中的位置而又不使用相对位移,一个Label类的唯一实例应被传入到visitLabel方法中。其它的MethodVisitor方法,比如visitJumpInsn, visitLookupSwitchInsn, visitTableSwitchInsn, visitTryCatchBlock, visitLocalVariablevisitLineNumber能够甚至在调用visitLabel之前使用这些Label实例。

    上面似乎听起来很复杂,因为这里需要读者具有对bytecode指令深入的了解。但是通过在被编译的类上使用ASMifierClassVisitor就能够使你看到ASM是如何生成任何指定的bytecode的,将ASMifier应用在两个被编译的类上(一个原始类、另一个是进行变换后的类),然后运行diff,输出结果将告诉你ASM在变换时调用了什么。这种处理揭示了在许多文章中的细节(见下面的资源)。这里提供一种用于 Eclipse IDE的插件,展示如图-4,此插件对生成ASM代码和比较ASMifier输出、在上下文中的bytecode引用提供了很好的支持。

    Eclipse ASM Plugin--click for full-size image.
    图-4 Eclipse ASM 插件

    通过ASM 访问者跟踪类的依赖性

    目前已经有一些文章解释了如何使用ASM生成bytecode(见下面的资源)。这里我们就不再赘述了,下面让我们看一下如何使用ASM对现有的类进行分析吧。这是一个有趣的应用:它能够捕捉任何指定模块或者.jar文件的外部类或者package的信息。为了简化起见,这个示例只捕获、输出依赖性,而不跟踪依赖物的类型(例如父类、方法参数、本地变量类型等)。

    请注意处于分析之目的,我们不需要为用于注释、字段、方法的子访问者创建新的实例。所有这些访问者,包括类、签名访问者都在下面的单一类中实现:

    public class DependencyVisitor implements
    AnnotationVisitor, SignatureVisitor,
    ClassVisitor, FieldVisitor, MethodVisitor {
    ...

    例如,我们将跟踪在package之间的依赖性,因此单独的类应该通过package名聚合在一起:

      private String getGroupKey(String name) {
    int n = name.lastIndexOf('/');
    if(n>-1) name = name.substring(0, n);
    packages.add(name);
    return name;
    }

    为了收集依赖性,例如ClassVisitor, AnnotationVisitor, FieldVisitorMethodVisitor的访问者接口应该有选择地聚合其方法所有的参数。下面是一些常见的示例:

    首先是 内部形式所用到的类名(父类、接口、异常、字段和方法拥有者);例如 java/lang/String

      private void addName(String name) {
    if(name==null) return;
    String p = getGroupKey(name);
    if(current.containsKey(p)) {
    current.put(p, current.get(p)+1);
    } else {
    current.put(p, 1);
    }
    }

    在这个示例中,current是依赖性的当前分组。

    另一个示例是类型描述符(注释、枚举、字段类型、新建数组指令的参数等);例如 Ljava/lang/String; J[[[I。它们将被Type.getType( desc)所解析来获得内部形式的类名:

      private void addDesc(String desc) {
    addType(Type.getType(desc));
    }

    private void addType(Type t) {
    switch(t.getSort()) {
    case Type.ARRAY:
    addType(t.getElementType());
    break;
    case Type.OBJECT:
    addName(t.getClassName().replace('.','/'));
    break;
    }
    }

    方法描述符用在方法声明、调用指令描述参数类型和返回类型;例如([java/lang/String;II)VType.getReturnType(methodDescriptor)Type.getArgumentTypes(methodDescriptor) 这两个帮助方法能够解析这样的描述符、并提取参数和返回类型。

      private void addMethodDesc(String desc) {
    addType(Type.getReturnType(desc));
    Type[] types = Type.getArgumentTypes(desc);
    for(int i = 0; i < types.length; i++) {
    addType(types[ i]);
    }
    }

    特殊的示例是用于一些"visit"方法中提供Java5类属信息的signature参数。如果它提供了类属信息,signature参数将覆盖描述符参数,并包含编码形式的类属信息。SignatureReader类能够用于解析这个值。因此我们能够实现用于签名的SignatureVisitor

      private void addSignature(String sign) {
    if(sign!=null) {
    new SignatureReader(sign).accept(this);
    }
    }

    private void addTypeSignature(String sign) {
    if(sign!=null) {
    new SignatureReader(sign).acceptType(this);
    }
    }

    实现ClassVisitor接口的方法,例如 visit(), visitField(), visitMethod()visitAnnotation(),它们能够收集关于父类、接口、字段类型、方法参数、返回值、异常、注释类型的依赖型信息。例如:

      public void visit(int version, int access,
    String name, String signature,
    String superName, String[] interfaces) {
    String p = getGroupKey(name);
    current = groups.get(p);
    if(current==null) {
    current = new HashMap<String,Integer>();
    groups.put(p, current);
    }

    if(signature==null) {
    addName(superName);
    addNames(interfaces);
    } else { addSignature(signature); } } public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { if(signature==null) { addDesc(desc); } else { addTypeSignature(signature); } if(value instanceof Type) { addType((Type) value); } return this; } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if(signature==null) { addMethodDesc(desc); } else { addSignature(signature); } addNames(exceptions); return this; } public AnnotationVisitor visitAnnotation( String desc, boolean visible) { addDesc(desc); return this; }

    实现MethodVisitor接口的方法能够收集关于参数注释的类型和用在bytecode指令中使用的对象引用的类型:

      public AnnotationVisitor
    visitParameterAnnotation(int parameter,
    String desc, boolean visible) {
    addDesc(desc); return this; } /** * Visits a type instruction * NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. */ public void visitTypeInsn(int opcode, String desc) { if(desc.charAt(0)=='[') { addDesc(desc); } else { addName(desc); } } /** * Visits a field instruction * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. */ public void visitFieldInsn(int opcode, String owner, String name, String desc) { addName(owner);
    addDesc(desc);
    } /** * Visits a method instruction INVOKEVIRTUAL, * INVOKESPECIAL, INVOKESTATIC or * INVOKEINTERFACE. */ public void visitMethodInsn(int opcode, String owner, String name, String desc) { addName(owner);
    addMethodDesc(desc);
    } /** * Visits a LDC instruction. */ public void visitLdcInsn(Object cst) { if(cst instanceof Type) { addType((Type) cst); } } /** * Visits a MULTIANEWARRAY instruction. */ public void visitMultiANewArrayInsn( String desc, int dims) { addDesc(desc); } /** * Visits a try catch block. */ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { addName(type); }

    现在我们能够使用DependencyVisitor来收集整个entire .jar的依赖性。例如:

      DependencyVisitor v = new DependencyVisitor();
    ZipFile f = new ZipFile(jarName);
    Enumeration<? extends ZipEntry> en = f.entries();
    while(en.hasMoreElements()) {
    ZipEntry e = en.nextElement();
    String name = e.getName();
    if(name.endsWith(".class")) {
    ClassReader cr =
    new ClassReader(f.getInputStream(e));
    cr.accept(v, false);
    }
    }

    被收集的信息能够表示为多种方式。其中一种就是建立依赖树、计算一些度量值,或者创建一些可视化图表。例如,图-5以简单的Java2D代码展示了ant.1.6.5.jar 的依赖性信息图表 。下面的图表在水平方向展示了 input .jar的package信息、在垂直方向展示了外部依赖性。方块的颜色深度表示了package被引用的次数。

    Dependencies in ant.1.6.5.jar as discovered with ASM
    图-5 ant.1.6.5.jar的依赖性

    完整的代码将在ASM的下一个版本中给出。不过你也可以通过ASM CVS获取。

    结论

    ASM2.0为开发者隐藏了一些bytecode的复杂性,它允许开发者在bytecode层高效地使用Java特性。本框架不但允许你变换、生成bytecode,而且还能提取出现有代码的重要细节。本API正在不断地改善中,2.0版本包含了J2SE5.0引入的类属和注释。在此之后,对Mustang(Java6.0)特性的支持已经被添加到了ASM框架中。

    资源

    引用:固定链接

    Java SE 6 新特性: HTTP 增强

    chris 发表于 2007-08-15 08:04:58
    作者:Matrix     来源:Matrix
    评论数:0 点击数:156     投票总得分:0 投票总人次:0
    关键字:Java SE 6;HTTP 增强

    摘要:
    Java SE 6 有着很多 HTTP 相关的新特性,使得 Java SE 平台本身对网络编程,尤其是基于 HTTP 协议的因特网编程,有了更加强大的支持。

    概述
      Java 语言从诞生的那天起,就非常注重网络编程方面的应用。随着互联网应用的飞速发展,Java 的基础类库也不断地对网络相关的 API 进行加强和扩展。在 Java SE 6 当中,围绕着 HTTP 协议出现了很多实用的新特性:NTLM 认证提供了一种 Window 平台下较为安全的认证机制;JDK 当中提供了一个轻量级的 HTTP 服务器;提供了较为完善的 HTTP Cookie 管理功能;更为实用的 NetworkInterface;DNS 域名的国际化支持等等。
    NTLM 认证
      不可避免,网络中有很多资源是被安全域保护起来的。访问这些资源需要对用户的身份进行认证。下面是一个简单的例子:

    import java.net.*;
    import java.io.*;

    public class Test {
     public static void main(String[] args) throws Exception {
      URL url = new URL("http://PROTECTED.com");
      URLConnection connection = url.openConnection();
      InputStream in = connection.getInputStream();
      byte[] data = new byte[1024];
      while(in.read(data)>0)
      {
       //do something for data
      }
      in.close();
     }
    }

      当 Java 程序试图从一个要求认证的网站读取信息的时候,也就是说,从联系于 http://Protected.com 这个 URLConnection 的 InputStream 中 read 数据时,会引发 FileNotFoundException。尽管笔者认为,这个 Exception 的类型与实际错误发生的原因实在是相去甚远;但这个错误确实是由网络认证失败所导致的。
      要解决这个问题,有两种方法:
      其一,是给 URLConnection 设定一个“Authentication”属性:
    String credit = USERNAME + ":" + PASSWORD;
    String encoding = new sun.misc.BASE64Encoder().encode (credit.getBytes());
    connection.setRequestProperty ("Authorization", "Basic " + encoding);

      这里假设 http://PROTECTED.COM 使用了基本(Basic)认证类型。
      从上面的例子,我们可以看出,设定 Authentication 属性还是比较复杂的:用户必须了解认证方式的细节,才能将用户名/密码以一定的规范给出,然后用特定的编码方式加以编码。Java 类库有没有提供一个封装了认证细节,只需要给出用户名/密码的工具呢?
      这就是我们要介绍的另一种方法,使用 java.net.Authentication 类。
      每当遇到网站需要认证的时候,HttpURLConnection 都会向 Authentication 类询问用户名和密码。
      Authentication 类不会知道究竟用户应该使用哪个 username/password 那么用户如何向 Authentication 类提供自己的用户名和密码呢?
      提供一个继承于 Authentication 的类,实现 getPasswordAuthentication 方法,在 PasswordAuthentication 中给出用户名和密码:
    class DefaultAuthenticator extends Authenticator {
     public PasswordAuthentication getPasswordAuthentication () {
      return new PasswordAuthentication ("USER", "PASSWORD".toCharArray());
     }
    }

      然后,将它设为默认的(全局)Authentication:
    Authenticator.setDefault (new DefaultAuthenticator()); 

      那么,不同的网站需要不同的用户名/密码又怎么办呢?
      Authentication 提供了关于认证发起者的足够多的信息,让继承类根据这些信息进行判断,在 getPasswordAuthentication 方法中给出了不同的认证信息:
    getRequestingHost() 
    getRequestingPort()
    getRequestingPrompt()
    getRequestingProtocol()
    getRequestingScheme()
    getRequestingURL()
    getRequestingSite()
    getRequestorType()  

      另一件关于 Authentication 的重要问题是认证类型。不同的认证类型需要 Authentication 执行不同的协议。至 Java SE 6.0 为止,Authentication 支持的认证方式有:
    HTTP Basic authentication 
    HTTP Digest authentication
    NTLM
    Http SPNEGO Negotiate
    Kerberos
    NTLM  

      这里我们着重介绍 NTLM。
      NTLM 是 NT LAN Manager 的缩写。早期的 SMB 协议在网络上明文传输口令,这是很不安全的。微软随后提出了 WindowsNT 挑战/响应验证机制,即 NTLM。
      NTLM 协议是这样的:
      ·客户端首先将用户的密码加密成为密码散列;
      ·客户端向服务器发送自己的用户名,这个用户名是用明文直接传输的;
      ·服务器产生一个 16 位的随机数字发送给客户端,作为一个 challenge(挑战) ;
      ·客户端用步骤1得到的密码散列来加密这个 challenge ,然后把这个返回给服务器;
      ·服务器把用户名、给客户端的 challenge 、客户端返回的 response 这三个东西,发送域控制器 ;
      ·域控制器用这个用户名在 SAM 密码管理库中找到这个用户的密码散列,然后使用这个密码散列来加密 challenge;
      ·域控制器比较两次加密的 challenge ,如果一样,那么认证成功;
      Java 6 以前的版本,是不支持 NTLM 认证的。用户若想使用 HttpConnection 连接到一个使用有 Windows 域保护的网站时,是无法通过 NTLM 认证的。另一种方法,是用户自己用 Socket 这样的底层单元实现整个协议过程,这无疑是十分复杂的。
      终于,Java 6 的 Authentication 类提供了对 NTLM 的支持。使用十分方便,就像其他的认证协议一样:
    class DefaultAuthenticator extends Authenticator {
     private static String username = "username ";
     private static String domain = "domain ";
     private static String password = "password ";

     public PasswordAuthentication getPasswordAuthentication() {
      String usernamewithdomain = domain + "/ "+username;
      return (new PasswordAuthentication(usernamewithdomain, password.toCharArray()));
     }
    }

      这里,根据 Windows 域账户的命名规范,账户名为域名+”/”+域用户名。如果不想每生成 PasswordAuthentication 时,每次添加域名,可以设定一个系统变量名“http.auth.ntlm.domain“。
      Java 6 中 Authentication 的另一个特性是认证协商。目前的服务器一般同时提供几种认证协议,根据客户端的不同能力,协商出一种认证方式。比如,IIS 服务器会同时提供 NTLM with kerberos 和 NTLM 两种认证方式,当客户端不支持 NTLM with kerberos 时,执行 NTLM 认证。
      目前,Authentication 的默认协商次序是:
    GSS/SPNEGO -> Digest -> NTLM -> Basic
      那么 kerberos 的位置究竟在哪里呢?
      事实上,GSS/SPNEGO 以 JAAS 为基石,而后者实际上就是使用 kerberos 的。
      轻量级 HTTP 服务器
      Java 6 还提供了一个轻量级的纯 Java Http 服务器的实现。下面是一个简单的例子:
    public static void main(String[] args) throws Exception{
     HttpServerProvider httpServerProvider = HttpServerProvider.provider();
     InetSocketAddress addr = new InetSocketAddress(7778);
     HttpServer httpServer = httpServerProvider.createHttpServer(addr, 1);
     httpServer.createContext("/myapp/", new MyHttpHandler());
     httpServer.setExecutor(null);
     httpServer.start();
     System.out.println("started");
    }

    static class MyHttpHandler implements HttpHandler{
     public void handle(HttpExchange httpExchange) throws IOException {
      String response = "Hello world!";
      httpExchange.sendResponseHeaders(200, response.length());
      OutputStream out = httpExchange.getResponseBody();
      out.write(response.getBytes());
      out.close();
     }
    }

      然后,在浏览器中访问 http://localhost:7778/myapp/,我们得到:
    image
    图一 浏览器显示
      首先,HttpServer 是从 HttpProvider 处得到的,这里我们使用了 JDK 6 提供的实现。用户也可以自行实现一个 HttpProvider 和相应的 HttpServer 实现。
      其次,HttpServer 是有上下文(context)的概念的。比如,http://localhost:7778/myapp/ 中“/myapp/”就是相对于 HttpServer Root 的上下文。对于每个上下文,都有一个 HttpHandler 来接收 http 请求并给出回答。
      最后,在 HttpHandler 给出具体回答之前,一般先要返回一个 Http head。这里使用 HttpExchange.sendResponseHeaders(int code, int length)。其中 code 是 Http 响应的返回值,比如那个著名的 404。length 指的是 response 的长度,以字节为单位。
    Cookie 管理特性
      Cookie 是 Web 应用当中非常常用的一种技术, 用于储存某些特定的用户信息。虽然,我们不能把一些特别敏感的信息存放在 Cookie 里面,但是,Cookie 依然可以帮助我们储存一些琐碎的信息,帮助 Web 用户在访问网页时获得更好的体验,例如个人的搜索参数,颜色偏好以及上次的访问时间等等。网络程序开发者可以利用 Cookie 来创建有状态的网络会话(Stateful Session)。 Cookie 的应用越来越普遍。在 Windows 里面,我们可以在“Documents And Settings”文件夹里面找到IE使用的 Cookie,假设用户名为 admin,那么在 admin 文件夹的 Cookies 文件夹里面,我们可以看到名为“admin@(domain)”的一些文件,其中的 domain 就是表示创建这些 Cookie 文件的网络域, 文件里面就储存着用户的一些信息。
      JavaScript 等脚本语言对 Cookie 有着很不错的支持。 .NET 里面也有相关的类来支持开发者对 Cookie 的管理。 不过,在 Java SE 6 之前, Java一直都没有提供 Cookie 管理的功能。在 Java SE 5 里面, java.net 包里面有一个 CookieHandler 抽象类,不过并没有提供其他具体的实现。到了 Java SE 6, Cookie 相关的管理类在 Java 类库里面才得到了实现。有了这些 Cookie 相关支持的类,Java 开发者可以在服务器端编程中很好的操作 Cookie, 更好的支持 HTTP 相关应用,创建有状态的 HTTP 会话。
      ·用 HttpCookie 代表 Cookie
      java.net.HttpCookie 类是 Java SE 6 新增的一个表示 HTTP Cookie 的新类, 其对象可以表示 Cookie 的内容, 可以支持所有三种 Cookie 规范:
      Netscape 草案
      RFC 2109 - http://www.ietf.org/rfc/rfc2109.txt
      RFC 2965 - http://www.ietf.org/rfc/rfc2965.txt
      这个类储存了 Cookie 的名称,路径,值,协议版本号,是否过期,网络域,最大生命期等等信息。
      ·用 CookiePolicy 规定 Cookie 接受策略
      java.net.CookiePolicy 接口可以规定 Cookie 的接受策略。 其中唯一的方法用来判断某一特定的 Cookie 是否能被某一特定的地址所接受。 这个类内置了 3 个实现的子类。一个类接受所有的 Cookie,另一个则拒绝所有,还有一个类则接受所有来自原地址的 Cookie。
      ·用CookieStore 储存 Cookie
      java.net.CookieStore 接口负责储存和取出 Cookie。 当有 HTTP 请求的时候,它便储存那些被接受的 Cookie; 当有 HTTP 回应的时候,它便取出相应的 Cookie。 另外,当一个 Cookie 过期的时候,它还负责自动删去这个 Cookie。
      ·用 CookieManger/CookieHandler 管理 Cookie
      java.net.CookieManager 是整个 Cookie 管理机制的核心,它是 CookieHandler 的默认实现子类。下图显示了整个 HTTP Cookie 管理机制的结构:
    image
    图 2. Cookie 管理类的关系
      一个 CookieManager 里面有一个 CookieStore 和一个 CookiePolicy,分别负责储存 Cookie 和规定策略。用户可以指定两者,也可以使用系统默认的 CookieManger。
      例子
      下面这个简单的例子说明了 Cookie 相关的管理功能:
    // 创建一个默认的 CookieManager
    CookieManager manager = new CookieManager();

    // 将规则改掉,接受所有的 Cookie
    manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);

    // 保存这个定制的 CookieManager
    CookieHandler.setDefault(manager);

    // 接受 HTTP 请求的时候,得到和保存新的 Cookie
    HttpCookie cookie = new HttpCookie("...(name)...","...(value)...");
    manager.getCookieStore().add(uri, cookie);

    // 使用 Cookie 的时候:
    // 取出 CookieStore
    CookieStore store = manager.getCookieStore();

    // 得到所有的 URI
    List<URI> uris = store.getURIs();
    for (URI uri : uris) {
    // 筛选需要的 URI
    // 得到属于这个 URI 的所有 Cookie
    List<HttpCookie> cookies = store.get(uri);
    for (HttpCookie cookie : cookies) {
     // 取出了 Cookie
    }
    }

    // 或者,取出这个 CookieStore 里面的全部 Cookie
    // 过期的 Cookie 将会被自动删除
    List<HttpCookie> cookies = store.getCookies();
    for (HttpCookie cookie : cookies) {
     // 取出了 Cookie
    }

    其他新特性
      ·NetworkInterface 的增强
      从 Java SE 1.4 开始,JDK 当中出现了一个网络工具类 java.net.NetworkInterface,提供了一些网络的实用功能。 在 Java SE 6 当中,这个工具类得到了很大的加强,新增了很多实用的方法。例如:
      public boolean isUp()
      用来判断网络接口是否启动并运行
      public boolean isLoopback()
      用来判断网络接口是否是环回接口(loopback)
      public boolean isPointToPoint()
      用来判断网络接口是否是点对点(P2P)网络
      public boolean supportsMulticast()
      用来判断网络接口是否支持多播
      public byte[] getHardwareAddress()
      用来得到硬件地址(MAC)
      public int getMTU()
      用来得到最大传输单位(MTU,Maximum Transmission Unit)
      public boolean isVirtual()
      用来判断网络接口是否是虚饨涌?
      关于此工具类的具体信息,请参考 Java SE 6 相应文档(见 参考资源)。
      ·域名的国际化
      在最近的一些 RFC 文档当中,规定 DNS 服务器可以解析除开 ASCII 以外的编码字符。有一个算法可以在这种情况下做 Unicode 与 ASCII 码之间的转换,实现域名的国际化。java.net.IDN 就是实现这个国际化域名转换的新类,IDN 是“国际化域名”的缩写(internationalized domain names)。这个类很简单,主要包括 4 个静态函数,做字符的转换。
    结束语
      Java SE 6 有着很多 HTTP 相关的新特性,使得 Java SE 平台本身对网络编程,尤其是基于 HTTP 协议的因特网编程,有了更加强大的支持。

    本页页面地址: http://www.matrix.org.cn/resource/article/2007-08-15/HTTP_297e66f9-4ac3-11dc-8d96-bf0b98a1a3c8.html

    July 26

    关于AspectJ 中的pointcut 语法(Z)

        这两天忙着看AspectJ in Action 为了补一下AOP知识。看了Spring 2.0的规范,其中AOP部分已经基本融合了AspectJ,看来有必要看一看AspectJ了。
       看了很多AOP的文章了,AOP这两年发展的很慢,没有什么新意,现在到处都是SOA,SCA了,不过研究了一下,觉得还是很有帮助的。尤其是增加系统的契约性和模块的独立性来说,很有帮助。
       当然,学东西,基础很重要。下面就说说AspectJ中的基本语法,有兴趣的可以看看AspectJ in Action。
       先来说说pointcut,从字面的意思说的是切面的意思。也就是横切的时候,会有哪些执行点会被识别。只有先识别了,才能执行相应的Advice。
       基本的定义如下:
       public pointcut accountOperations:call(* Account.*(..))
    1.通配符和pointcut 操作符

    • *  表示任何数量的字符,除了(.)
    • .. 表示任何数量的字符包括任何数量的(.)
    •        + 描述指定类型的任何子类或者子接口
    同java一样,提供了一元和二元的条件表达操作符。
    一元操作符:!
    二元操作符:||和&&
    优先权同java
        2.签名语法
    类型签名样式
    主要的例子:
    Account 类型Account
    *Account                             使用Account名称结束的类型,如SavingsAccount和CheckingAccount
    java.*.Date                         类型Date在任何直接的java子包中,如java.util.Date和java.sql.Date
    java..*                                 任何在java包或者所有子包中的类型,如java.awt和java.util或者java.awt.event 和java.util.logging
    javax..*Model+                   所有javax包或者子包中以Model结尾的类型和其所有子类,如TableModel,TreeModel。
    !vector 所有除了Vector的类型
    Vector|| Hashtable Vector或者Hashtable类型
    java.util.RandomAccess+ 实现RandomAccess和List的所有子类
    && java.util.List+
    方法和构造器签名模式
      public void Collection.clear():
    在Collection中同样签名的clear方法
      public void Account.debit(float) throws InsufficientBalanceException:
    Account中同样签名的debit方法
      public void Account.set*(*)
    Account中以set开头,并且只有一个参数类型的方法
      public void Account.*()
    Account中所有的没有参数的public void 方法
      public * Account.*()
      Account中所有没有参数的public 方法
      public * Account.*(..)
    Account中所有的public 方法
      * Account.*(..)
    Account中的所有方法,包括private方法
      !public * Account.*(..)
    所有的非public 方法
       * Account+.*(..)
    所有的方法,包括子类的方法
       * java.io.Reader.read(..)
    所有的read方法
       * java.io.Reader.read(char[],..)
    所有以read(char[])开始的方法,包括read(char[])和read(char[],int,int)
       * javax..*.add*Listener(EventListener+)
    命名以add开始,以Listener结尾的方法,参数中为EventListener或子类
       * *.*(..) throws RemoteException
    抛出RemoteException的所有方法
       构造器,同上面
       public Account.new()
    没有参数的构造器方法
    属性签名模式
        同方法一样,属性也查不多
    * Account.*  
        所有的Account属性
    !public static * banking..*.*
        所有的非public static 属性,在banking的包或者子包中
    3.主要的pointcuts类型
    分类pointcuts
        遵循特定的语法用于捕获每一个种类的可使用连接点。
        主要的种类:
    • 方法执行:execution(MethodSignature)
    • 方法调用:call(MethodSignature)
    • 构造器执行:execution(ConstructorSignature)
    • 构造器调用:call(ConstructorSignature)
    • 类初始化:staticinitialization(TypeSignature)
    • 属性读操作:get(FieldSignature)
    • 属性写操作:set(FieldSignature)
    • 例外处理执行:handler(TypeSignature)
    • 对象初始化:initialization(ConstructorSignature)
    • 对象预先初始化:preinitialization(ConstructorSignature)
    • Advice执行:adviceexecution()
    基于控制流的pointcuts
       主要包括两种类型的控制流:
       cflow(Pointcut),捕获所有的连接点在指定的方法执行中,包括执行方法本身。
       cflowbelow(Pointcut),捕获所有的连接点在指定的方法执行中,除了执行方法本身。
       如以下的例子:
    cflow(call(* Account.debit(..))
       所有的debit方法中的连接点,包括debit方法本身
    cflowbelow(call(* Account.debit(..))
       所有debit方法中的连接点,除了debit方法本身
    cflow(transactedOperations())
       所有由transactedOperations捕获的连接点
    cflowbelow(execution(Account.new(..))
       所有在Account 构造器中执行的连接点
    基于词汇结构的连接点
       源代码片断。,如within()和withincode()
       within :捕获在指定类或者方面中的程序体中的所有连接点,包括内部类。
       Withincode:用于捕获在构造器或者方法中的所有连接点,包括在其中的本地类
    执行对象连接点
       匹配this,和target对象,作为方法被调用的对象。
       this(Account),所有Account的实例的执行点,匹配所有的连接点,如方法调用,属性设置,当前的执行对象为Account,或者其子类。
       target(Account):匹配所有的连接点,目标对象为Account或其子类。
       必须执行相应的类型,不能使用*,或者..通配符。当前静态方法,不能被匹配。
       在within()和this()中的区别:
       一个是程序体,而另一个为对象执行。
    参数pointcuts
       用于捕获参数类型的连接点。
       args(String,..,int)
       args(RemoteException)
    条件检测pointcuts
       if(System.currentTimeMillis()>triggerTime)
       基本的语法就这些,不过AspectJ5 已经增加了不少语法,主要关于Annotation 的,不过这部分还没有仔细研究,以后再讲解吧。希望能有所帮助
    June 06

    一个成年男子的暴笑日记(Z)

    我知道我不算帅哥,但曾经有人看我满月的照片时,也说过我左边的鼻孔很偶像派。  
      8月30日  
        独守空房,让人只能浪费;妻妾成群,让人懂得节俭。可是我现在,却在终日浪费中向往节俭。  
      5月10日  
        我想我是个变态,我有恋母和喜欢极品熟女的癖好。不然为什么每次看到我们超市主管的那张脸,我都想操她奶奶?  
      3月18日  
        和女朋友分手之后,我终于明白,幸福要掌握在自己的手中,而不是在别人的嘴里!  
      7月9日  
        今天看书,看到康熙皇帝在二十三岁的时候已经贵为一国之君,绩伟功丰,我很沮丧;但又看到同治皇帝在二十三岁时已经死了四年了,我平饬恕?  
      11月11日  
        情人节,孤单的我在饭馆吃面,听到收音机里的点歌节目说:“有一位先生给所有恋人们点歌来表达他的祝福,下面请听《无言的结局》。”……我觉得很不好,人可以无爱,但不能无耻,于是我也打电话点播了一首歌——梁静茹的《分手快乐》。  
      7月20日  
        以前喜欢过一个女孩,表白了,那女孩问我为什么喜欢她,我说:如果你是我,也会喜欢上你自己的;  
        后来,她把我拒绝了,我很伤心,她不了解我,我告诉她:如果我是你,肯定早就喜欢上我自己了!  
      12月9日  
        今天饭馆的白酒又兑水了!**!等我有钱了,也到大酒楼去喝人头马、XO什么的!而且绝对不让他们用八六年和七二年的糊弄我,要喝就来瓶今年的!  
      9月12日  
        其实馒头是万能的,饿了就可以吃。想吃饼,就把馒头拍扁;想吃面条,就把馒头用梳子梳;想吃汉堡,就把馒头切开夹菜吃……  
      9月12日  
        男人,上半身是修养,下半身是本质;女人,上半身是诱饵,下半身是陷阱。  
      9月10日  
        单身很痛苦,单身久了更痛苦,前几天我看见一头母猪,都觉得它眉清目秀的……  
      6月22日  
        男人分两种,一种是好色,一种是十分好色;  
        女人也分两种,一种是假装清纯,一种是假装不清纯。  
      1月19日  
        有些人的爱情是A片,有些是三级片,有些是喜剧片,有些是文艺片;  
        我最惨,我的爱情过程是文艺片、喜剧片、三级片、A片、悬疑片、动作片,最后是KB片,更可气的是,还他 妈插播广告……  
      2月13日  
        明天情人节,我辗转找到一个我中学暗恋的女生的电话,给她发了一条短信:如果只有一碗粥,你先喝半碗,剩下的半碗,我放在怀里给你保温……  
        几分钟后,她回了一条短信:你是谁介绍的?一次四百,包夜七百。  
      2月14日  
        舍不得孩子套不着狼,舍不得媳妇抓不着流氓,舍不得更新得不着收藏……  
        今天心情一直不好,昨晚的短信让我知道了,我以前暗恋的女生堕落了,竟然跟我说一次四百……  
        当时我很伤心,一边伤心一边翻了翻钱包:  
        于是我更伤心了,我连陪她堕落一次的资本都没有……  
      4月15日  
        你问我,幸福在哪里?我告诉你,你踮起脚尖,就能离幸福更近一些,你闭上眼,就能感受到幸福了……  
        许久,我们分开,我看着你羞红的脸颊,轻声问你,感觉到幸福了么?  
        你温柔的低头,娇声回了一句:你今天,吃蒜了。  
      5月10日  
        什么叫残忍?  
        是男人,我就打断他三条腿;是公狗,我就打断它五条腿!  
      6月9日  
        今天心情不好。我只有四句话想说。包括这句和前面的两句。我的话说完了……  
      7月23日  
        对付凶恶的人,就要比他更凶恶;对付卑鄙的人,就要比他更卑鄙;  
        对付潇洒的人,就要比他更潇洒;对付英俊的人,就要……毁他的容!  
      7月23日  
        上一次恋爱给我的教训是:不要找一个喜欢吃辣的女孩作女朋友。  
        每一次请她吃完麻辣火锅,我们在一起亲热时,我都会在痛苦不堪中想起一首歌:《燃烧吧!火鸟》。  
      5月23日  
        我的原则是:人不犯我,我不犯人;人若犯我,我就生气!  
      5月23日  
        忽然想起上大学时,老师出对联:国兴旺,家兴旺,国家兴旺。  
        班长对下联:天恢弘,地恢弘,天地恢弘!  
        后来我被赶出了教室……  
        因为我对的下联是:你 妈 的,他 妈 的,你 他 **!  
      5月23日  
        偶然看见书上所谓的当代女子择偶标准:有车有房,父母双亡。  
        郁闷。遂写下幻想中的选妻标准:  
        家中财产过亿,美貌天下第一,贤惠温柔性感,岳父癌症晚期……  
      7月17日  
        凤凰重生就是涅盘,野鸡重生就是尸变。  
      7月11日  
        人生啊,不能在一棵树上吊死,要在附近几棵树上多死几次试试。  
      8月18日  
        我才发现,吸引住男人的办法就是让他一直得不到;吸引女人的办法正好相反,就是让她一直满足。  
      9月8日  
        人生的悲惨在于:辛辛苦苦的作了一晚上内容香艳的美梦,第二天早上醒来居然全都记不起来了!  
      5月19日  
        这个世界不公平就在于:  
        上帝说:我要光!——于是有了白天。  
        美女说:我要钻戒!——于是她有了钻戒。  
        富豪说:我要女人!——于是他有了女人。  
        我说:我要洗澡!——居然停水了!  
      5月8日  
        吃了晚饭在阳台抽烟享受,忽见夜空中一个光点转瞬即逝的划过,心里一激动:流星!于是马上许愿……  
        许了六七个愿望,睁眼,烟已经抽完了,顺手扔出阳台,忽然听见楼下一个女孩的声音:“哇!流星!快许愿……”

    March 21

    log4j配置文件格式(Z)

           在实际编程时,要使Log4j真正在系统中运行事先还要对配置文件进行定义。定义步骤就是对Logger、Appender及Layout的分别使用。Log4j支持两种配置文件格式,一种是XML格式的文件,一种是java properties(key=value)【Java特性文件(键=值)】。(这里只说明properties文件)

    1、配置根Logger

          其语法为:
          log4j.rootLogger = [ level ] , appenderName1, appenderName2, …
          level : 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定 义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。appenderName:就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。
         例如:log4j.rootLogger=info,A1,B2,C3

    2、配置日志信息输出目的地

          其语法为:
          log4j.appender.appenderName = fully.qualified.name.of.appender.class  //
          "fully.qualified.name.of.appender.class" 可以指定下面五个目的地中的一个:

              1.org.apache.log4j.ConsoleAppender(控制台)
              2.org.apache.log4j.FileAppender(文件)
              3.org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
              4.org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
              5.org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

                 1.ConsoleAppender选项
                        Threshold=WARN:指定日志消息的输出最低层次。
                        ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
                        Target=System.err:默认情况下是:System.out,指定输出控制台
                  2.FileAppender 选项
                        Threshold=WARN:指定日志消息的输出最低层次。
                        ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
                        File=mylog.txt:指定消息输出到mylog.txt文件。
                        Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
                3.DailyRollingFileAppender 选项
                        Threshold=WARN:指定日志消息的输出最低层次。
                        ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
                        File=mylog.txt:指定消息输出到mylog.txt文件。
                        Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
                        DatePattern='.'yyyy-ww:每周滚动一次文件,即每周产生一个新的文件。当然也可以指定按月、周、天、时和分。即对应的格式如下:
                        1)'.'yyyy-MM: 每月
                        2)'.'yyyy-ww: 每周
                        3)'.'yyyy-MM-dd: 每天
                        4)'.'yyyy-MM-dd-a: 每天两次
                        5)'.'yyyy-MM-dd-HH: 每小时
                        6)'.'yyyy-MM-dd-HH-mm: 每分钟
                4.RollingFileAppender 选项
                        Threshold=WARN:指定日志消息的输出最低层次。
                        ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
                        File=mylog.txt:指定消息输出到mylog.txt文件。
                        Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
                        MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时,将会自动滚动,即将原来的内容移到mylog.log.1文件。
                        MaxBackupIndex=2:指定可以产生的滚动文件的最大数。

    3、配置日志信息的格式

            其语法为:
      1). log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
                  "fully.qualified.name.of.layout.class" 可以指定下面4个格式中的一个:
                   1.org.apache.log4j.HTMLLayout(以HTML表格形式布局),
             2.org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
             3.org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
             4.org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
                       1.HTMLLayout 选项
                          LocationInfo=true:默认值是false,输出java文件名称和行号
                          Title=my app file: 默认值是 Log4J Log Messages.
                       2.PatternLayout 选项
                          ConversionPattern=%m%n :指定怎样格式化指定的消息。
                       3.XMLLayout  选项
                          LocationInfo=true:默认值是false,输出java文件和行号

            2). log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
               这里需要说明的就是日志信息格式中几个符号所代表的含义:
               -X号: X信息输出时左对齐;
                       %p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
                       %d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
                       %r: 输出自应用启动到输出该log信息耗费的毫秒数
                       %c: 输出日志信息所属的类目,通常就是所在类的全名
                       %t: 输出产生该日志事件的线程名
                       %l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
                       %x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
                       %%: 输出一个"%"字符
                       %F: 输出日志消息产生时所在的文件名称
                       %L: 输出代码中的行号
                       %m: 输出代码中指定的消息,产生的日志具体信息
                       %n: 输出一个回车换行符,Windows平台为"\r\n",Unix平台为"\n"输出日志信息换行
                可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
                         1)%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
                         2)%-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。
                         3)%.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
                         4)%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉。

                      

    March 15

    Linux网络资源

    这是某位大大总结的好东东,网上看见,收藏了!
    gearbox
    2004-07-28, 00:56
    CODE
    第一部分:Linux基础应用
    1、《Linux从入门到精通》
    http://www.gouhuo.com/study/linuxbook.zip
    2、 Linux 系统安全与优化中文版
    这本书的英文版“Get Acquainted with Linux Security and Optimization System”(简称LinuxSOS)是Linux文档计划(Linux Document Project)中比较新的一本指南。这本书不是Linux的入门书籍,读这本书需要有Linux或者Unix的背景知识。如果你已经安装过Linux而且能够使用一些简单的Unix命令,那么这本书会对你有很大的帮助。
    http://www.linuxaid.com.cn/download/training/linuxsos-cn.pdf
    4、Linux编程白皮书.zip 13-Aug-2002 16:14 16M
    http://cpss.zz.ha.cn/study/linux/Linux%b1%e0%b3%cc%b0%d7%c6%a4%ca%e9.zip
    6、Linux系统分析与高级编程 13-Aug-2002 16:14 11M
    http://cpss.zz.ha.cn/study/linux/Linux%cf%b5%cd%b3%b7%d6%ce%f6%d3%eb%b8%df%bc%b6%b1%e0%b3%cc%bc%bc%c a%f5.zip
    7、Linux系统管理白皮书.zip 13-Aug-2002 16:14 6.8M
    http://cpss.zz.ha.cn/study/linux/Linux%cf%b5%cd%b3%b9%dc%c0%ed%b0%d7%c6%a4%ca%e9.zip
    8、Linux应用程序开发指南 13-Aug-2002 16:14 9.1M
    http://cpss.zz.ha.cn/study/linux/Linux%d3%a6%d3%c3%b3%cc%d0%f2%bf%aa%b7%a2%d6%b8%c4%cf%a3%ba%ca%b9%d 3%c3Gtk+%20Gnome%bf%e2.zip
    9、Linux 24学时教程.zip 13-Aug-2002 16:14 34M
    http://cpss.zz.ha.cn/study/linux/Linux%2024%d1%a7%ca%b1%bd%cc%b3%cc.zip
    10、Red Hat Linux 6大全.zip 13-Aug-2002 16:15 33M
    http://cpss.zz.ha.cn/study/linux/Red%20Hat%20Linux%206%b4%f3%c8%ab.zip
    11、Red Hat Linux 6管理工具 13-Aug-2002 16:15 13M
    http://cpss.zz.ha.cn/study/linux/Red%20Hat%20Linux%206%b9%dc%c0%ed%b9%a4%be%df.zip
    12、http://www.linuxsir.org/pdf/ebook1.rar
    http://www.linuxsir.org/pdf/ebook2.rar
    具体文章如下:
    基础建设讨论专版:
    Linux管理员手册
    linux入门教程
    linux指令大全
    红旗版区的:
    红旗桌面4正式版最新使用方法和问题解答100例
    Linux shell进阶应用与shell编程
    命令大集合
    TCSH shell 编程
    Bourne Shell及shell编程
    Linux Shell简介
    脚本精华欣赏
    使用 Bash shell 脚本进行功能测试
    Linux 发行版SuSE专题
    SuSE 解决方案
    13、Debian的中文FAQ 600k pdf
    http://linuxdoc.51.net/download/Debian_cn_FAQ.pdf
    14、Linux Kernel 核心手册(中文)552k zip
    http://linuxdoc.51.net/download/Linux_Kernel_cn.zip
    17、SuSE官方汉化手册 1.4M pdf
    http://linuxdoc.51.net/download/suse_guanfang_hanhua.pdf
    19、Linux程序员指南 337k zip
    http://linuxdoc.51.net/download/linux_program.zip
    22、FreeBSD使用大全(Chm格式)
    是王波写的一本专门介绍Freebsd的书籍,共94章,图文并茂,是不可多得的FreeBSD方面的教材。
    http://www.linuxdby.com/downloadlink.php?id=15
    23、Redhat 9.0 官方中文安装指南
    http://www.fcitx.org/flysail/rhl-ig-x86-zh_CN-9.tar.gz
    Redhat 9.0 官方中文入门指南
    http://www.fcitx.org/flysail/rhl-gsg-zh_CN-9.tar.gz
    Redhat 9.0 官方中文定制指南
    http://www.fcitx.org/flysail/rhl-cg-zh_CN-9.tar.gz
    24、《Linux 新手管理员指南》
    本书《Linux 新手管理员指南》是英文版LINUX NEWBIE ADMINISTRATOR GUIDE 的完整中文译本,共237页,PDF格式。
    原版:http://linux-newbie.sunsite.dk/
    下载:http://www.linuxdby.com/downloadlink.php?id=51
    25、Linux高级配置详解(PDG)
    讲述在Linux操作系统下的软、硬件配置、网络应用配置、X Window系统配置以及内核的配置和编译等知识。
    http://www.mycodes.net/down.asp?id=793&no=1
    http://www.mycodes.net/down.asp?id=793&no=2
    gearbox
    2004-07-28, 00:58
    QUOTE
    第二部分:Linux系统管理
    1、Setting up a Local Area Network (EN)上载:5/9/2002
    http://www.joyfire.net/compress/rh-lan.pdf
    2、linux for mainframe (EN)上载:5/9/2002
    http://www.joyfire.net/compress/linux4mainframe.zip
    3、Linux Consultants Guide (EN)上载:1/9/2002
    http://www.joyfire.net/compress/Consultant...ide.html.tar.gz
    5、Red Hat Network Basic User Reference Guide (EN)上载:13/7/2002
    http://www.joyfire.net/compress/rhn-basic-urg-en-3.3.tgz
    6、Red Hat Network Enterprise User Reference Guide (EN)上载:13/7/2002
    http://www.joyfire.net/compress/rhn-enterp...-urg-en-1.1.tgz
    8、Linux系统分析与高级编程技术上载:4/5/2002
    http://www.joyfire.net/compress/linux_adva..._technology.zip
    9、RedHat Linux网络管理工具上载:4/5/2002
    http://www.joyfire.net/compress/RadHat_Lin...nt_Tools_CN.zip
    10、Linux管理指南上载:4/5/2002
    http://www.joyfire.net/compress/Linux_Management_CN.zip
    11、GNU Linux 高级网络应用服务指南上载:4/5/2002
    http://www.joyfire.net/compress/GNU_linux_...twork_Guide.zip
    l
    12、inux环境数据库管理员手册上载:4/5/2002
    http://www.joyfire.net/compress/Linuxdb.zip
    13、Complete Linux Command Reference (EN)上载:4/5/2002
    http://www.joyfire.net/compress/Complete_L...d_Reference.zip
    14、Bugzilla-Guide (EN) 上载:20/4/2002
    http://www.joyfire.net/compress/Bugzilla-Guide.html.tar.gz
    17、Advanced Bash-Scripting Guide(EN) 在线浏览 上载:11/3/2002
    http://www.joyfire.net/compress/abs-guide.html.tar.gz
    http://www.joyfire.net/abs-guid/index.html
    18、Securing and Optimizing Linux RedHat Edition -A Hands on Guide(EN) 在线浏览 上载:11/3/2002
    http://www.joyfire.net/compress/Securing-O...1.3.html.tar.gz
    http://www.joyfire.net/solrhe/Securing-Opt...v1.3/index.html
    20、The Linux System Administrators' Guide(EN) 在线浏览 中文版上载:1/1/2002。
    http://www.joyfire.net/compress/sag.html.tar.gz
    http://www.joyfire.net/sag/index.html
    http://www.joyfire.net/compress/Linuxsys.zip
    21、The Linux Network Administrator's Guide, 2e (EN) 在线浏览 上载:1/1/2002
    http://www.joyfire.net/compress/nag-2.0.html.tar.gz
    http://www.joyfire.net/nag2/index.html
    22、Linux System Administration Made Easy (EN) 在线浏览 上载:1/1/2002
    http://www.joyfire.net/compress/lame.html.tar.gz
    http://www.joyfire.net/lame/index.html
    23、AKA讲座(a link)上载:1/1/2002
    http://bj.aka.org.cn/Lectures/index.html
    24、ORACLE for linux install handbook (EN)上载:1/1/2002
    http://www.joyfire.net/compress/installguide_linu
    October 25

    [转]三言二拍:实名这档子事

    很多人说,管理是门艺术,这是瞎扯。最简单、最直接的管理,别说艺术,连技术都算不上,勉强可以说是算术——算计的算,盘算的算,清算的算,秋后算账的算。

    校园BBS上经常有些情绪帖,还找不到发帖人,让领导很是头痛——这很简单,实名,禁止校外IP发帖;手机短信经常出现诈骗、传递非法信息等问题,还找不到机主,让领导很是头痛——这很简单,实名,一卡对一人;blog猛不丁就有了1000多万用户,七嘴八舌,想说啥说啥,让领导很是头痛——这很简单,实名,一萝卜一坑。

    实名,说白了,就是让你时时刻刻记得,老大哥炯炯的目光一直在背后盯着你。你是坏人,是暴民,是潜在的罪犯,但你什么坏事儿都不敢干。就像监考老师目不转睛地盯着你,就算你有作弊的心,恐怕也没作弊的胆。这叫威慑力,出门都怕被树叶砸破头的升斗小民,哪抗得住这阵势,早被威慑得只剩筛糠的份了。

    有人说,你不干坏事,怕实名作甚?说这种话的,纯属猪头。这种人可能已经习惯了一天到晚有人盯梢,习惯了在自家做个爱都有摄像头监视着,习惯了腹诽几句领导都会被蛔虫给汇报了。

    互联网协会秘书长黄澄清说:中国互联网协会博客研究小组建议的博客实名制是有限实名、后台实名,即网民在向网站提供信息登记开设博客时使用实名,在博客写作中仍可使用网名。貌似很温婉,很宽宏大量。言外之意,除了我,仍然没人知道你是一条狗,别怕。废话,怕的就是你。

    中国人把有限的钱,都花在这种管理算术上,难怪在推动社会进步的技术上,总也没什么创新。

    September 27

    BlogThisSong

    BlogThisSong.com,你可以:

    • 搜索到你喜欢的歌曲,并且使用一个超酷的带歌词Flash MP3播放器直接试听;
    • 把你喜欢的歌曲和这个超酷播放器直接放在你的BLOG上;
    • TOP100最流行歌曲直接带歌词试听;
    • 使用WordPress的朋友可以直接下载并使用WordPress插件进行Blog This Song。

    (Publish by Windows Live Writer :P )