2009年6月17日

文档选项
将打印机的版面设置成横向打印模式

打印本页

将此页作为电子邮件发送

将此页作为电子邮件发送

未显示需要 JavaScript 的文档选项


级别: 初级

隋 鹏飞 (suipf@cn.ibm.com), 软件工程师, IBM
伍 亦方 (wuyifang@cn.ibm.com), 软件工程师, IBM

2009 年 3 月 11 日

本文将向读者介绍利用 Java dump 诊断 JVM Crash 和 CPU 饥饿等问题的方法和技巧,以便使用户更加全面的了解 Java dump 在故障诊断过程中的作用。

更多关于 Java dump 进行 JVM 故障诊断的内容,请参考:

  • 在 WAS V6.1 应用程序中跟踪死锁:本文讲述了如何使用 WAS V6.1 中的线程转储工具了解您的系统环境,检查是否发生死锁以及提取信息来帮助避免或解决自己应用程序的死锁情况。

 

本文对上面的文章做了进一步的补充,介绍了如何利用 Java dump 诊断 JVM Crash 和 CPU 饥饿等问题的方法和技巧。

引言

对于大型 java 应用程序来说,再精细的测试都难以堵住所有的漏洞,即便我们在测试阶段进行了大量卓有成效的工作,很多问题还是会在生产环境下暴露出来,并且很难在测试环境中进行重现。JVM 能够记录下问题发生时系统的运行状态并将其存储在转储(dump)文件中,从而为我们分析和诊断问题提供了重要的依据。常见的转储文件包括 Java Dump, Heap dump 和 System dump。这里我们主要介绍 Java dump 在 JVM 故障诊断中的应用。

Java dump,也叫做 Thread dump,是 JVM 故障诊断中最重要的转储文件之一。JVM 的许多问题都可以使用这个文件进行诊断,其中比较典型的包括线程阻塞,CPU 使用率过高,JVM Crash,堆内存不足,和类装载等问题。作为一款轻量级(与 Heap dump 和 System dump 相比)的转储文件,Java dump 的确是我们诊断 JVM 问题的首选。本文将系统的介绍使用 Java dump 进行 JVM 故障诊断的方法和技巧,希望能够为大家提供一些帮助。





回页首


Java dump 文件的格式和内容

Java dump 通常是文本格式(.txt),因此可以通过一般的文本编辑器进行阅读,阅读时需要注意段与行的格式:

段格式

为了便于大家的分析,Java dump 的每一段的开头,都会用“-----”与上一段明显的区分开来。而每一段的标题也会用“=====”作为标识,这样我们就能够很容易的找到每一段的开头和标题部分(如清单 1)。


清单 1. Java dump 段标题示例
NULL --------------------------------
            0SECTION TITLE subcomponent dump routine
            NULL ===============================
            

行格式

Java dump 文件中,每一行都包含一个标签,这个标签最多由 15 个字符组成(如清单2中所示)。其中第一位数字代表信息的详细级别(0,1,2,3,4),级别越高代表信息越详细;接下来的两个字符是段标题的缩写,比如,“CI” 代表 “Command-line interpreter”,“CL” 代表 “Class loader”,“LK” 代表 “Locking”,“ST” 代表 “Storage”,“TI” 代表 “Title”,“XE” 代表 “Execution engine”等等;其余部分为信息的概述。


清单 2. Java dump 行标签和内容示例
1TISIGINFO Dump Event "uncaught" (00008000) Detail "java/lang/OutOfMemoryError" received

不同版本的 JVM 所产生的 Java dump 的格式可能会稍有不同,但基本上都会包含以下几个方面的内容:

  • TITLE 信息块:描述 JAVA DUMP 产生的原因,时间以及文件的路径。
  • GPINFO信息块:GPF 信息。
  • ENVINFO 信息块:系统运行时的环境及 JVM 启动参数。
  • MEMINFO 信息块:内存的使用情况和垃圾回收记录。
  • LOCKS 信息块:用户监视器(Monitor)和系统监视器(Monitor)。
  • THREADS信息块:所有 java 线程的状态信息和执行堆栈。
  • CLASSES信息块:类加载信息。




回页首


利用 Java Dump 进行 JVM 故障诊断

由于 Java dump 文件包含的内容比较广泛,因此 JVM 的很多问题都可以通过 java dump进行诊断。这些问题主要包括线程阻塞,CPU 使用率过高,JVM Crash,堆内存不足,和类装载等问题。

诊断线程阻塞问题

线程阻塞是我们在 java 多线程编程中经常遇到的问题。由于对后端有限资源的争用以及过度同步等问题,经常会发现 Java dump 中某个资源(锁对象)下有太多的线程处于等待状态,这时候我们通常需要从以下三个方面去诊断这个问题:

  • 这个锁存在的目的是什么?有没有可能去掉这个锁或者缩小这个锁保护的范围,从而减少线程等待问题发生的几率。
  • 有哪些线程需要用到这个锁,有没有可能改用其它更好的替代方案。
  • 当前哪个线程正在持有这个锁,持有的时间是多长,有没有可能缩短持有的时间。

比线程阻塞更严重的是死锁问题,当两个以上的线程互相等待对方的锁,从而形成一个环的时候,就会发生死锁。关于如何使用 Java dump 诊断死锁的问题,请参考 在 WebSphere Application Server V6.1 应用程序中跟踪死锁 一文,该文对此问题做了较为详细的介绍。

诊断 JVM Crash 问题

JVM Crash 是我们所碰到的最棘手的问题之一,它对整个系统的影响是致命的,并且总是让人防不胜防。导致 JVM 崩溃的原因有很多,通常都是一些底层的错误。比如 JVM 本身的 bug,错误的 JNI 调用,第三方原生模块(比如数据库驱动程序)中的 bug 等。JVM崩溃的原因复杂,并且大多都难以重现,所以诊断起来有一定的难度。

一般来说,JVM 崩溃的时候,系统一般会自动产生一个 Java dump 文件(JVM 默认的设置参数就会触发)。这个 Java dump 会帮我们记录下 JVM 崩溃的原因,相关的信息会记录在 TITLE 信息块,GPINFO 信息块和 THREADS 信息块中。

  • TITLE 信息块:用于确认问题产生的原因,即是否是由于一些底层错误而导致 JVM Crash。
  • GPINFO 信息块:用于查看问题的详细信息和问题定位。
  • THREADS信息块:用于了解问题线程的运行情况。

下面我们通过一个具体的例子来介绍 JVM Crash 问题的诊断方法。TestJni 是一个简单的 Java 应用,它通过 JNI 调用本地代码 CallJin.dll 中的 doSomeThing() 函数。


清单 3. 在 TestJni 类中调用 CallJin.dll 中的函数
package test;
            public class TestJin {
            /**
            * @param args
            */
            public static void main(String[] args) {
            // TODO Auto-generated method stub
            TestJin testObj = new TestJin();
            testObj.work();
            }
            public void work() {
            CallJni.doSomeThing();
            }
            }
            package test;
            public class CallJni {
            static
            {
            System.loadLibrary("CallJni");
            System.out.println("Dll Loaded");
            }
            public native static void doSomeThing();
            }
            

CallJin.dll 是 C++ 编写得本地库,其源代码如清单 3 所示:


清单 4. CallJni.dll 的 C++ 实现代码
#include <com_test_CallJni.h>
            /*
            * Class:     com_test_CallJni
            * Method:    doSomeThing
            */
            JNIEXPORT void JNICALL Java_test_CallJni_doSomeThing
            (JNIEnv *, jclass){
            int *i;
            *i = 100;
            }
            

在这段 C++ 代码中,整形指针 I 还没有分配空间就被赋了值,这是一个非常严重的错误。当然 java 应用程序员并不知道这一点,并且在 java 应用程序中调用了 doSomeThing() 这个 JNI 函数。结果导致 JVM 发生了崩溃。

在这段 C++ 代码中,整形指针 I 还没有分配空间就被赋了值,这是一个非常严重的错误。当然 java 应用程序员并不知道这一点,并且在 java 应用程序中调用了 doSomeThing() 这个 JNI 函数。结果导致 JVM 发生了崩溃。

下面是 JVM 崩溃时,系统为我们生成的 Java dump 文件的片断。


清单5. Java dump 文件片断
NULL           ----------------------------------------------
            0SECTION       TITLE subcomponent dump routine
            NULL           ===============================
            1TISIGINFO     Dump Event "gpf" (00002000) received
            1TIDATETIME    Date:                 2008/11/12 at 20:45:24
            1TIFILENAME Javacore filename:
            C:\eclipse\workspace\Serviceability\TestApps\SampleLeak\TestJin\
            javacore.20081112.204522.5656.txt
            

从 TITLE 信息块中我们可以看到,这个 java 是由一个 "gpf" 事件触发的,GPF 是 General Protection Fault 的缩写,表明应用程序发生了一般性保护错误,这种错误常常导致 JVM 突然崩溃。

除了 "gpf" 之外,Java dump 还可能由如下事件触发(清单 6)。


清单 6. 常见 Java dump 触发事件
user       SIGQUIT signal (Ctrl-Brk on Windows, Ctrl-\ on Linux, Ctrl-V on z/OS)
            abort      a controlled crash, as triggered by the abort() system call
            vmstart    the VM has finished initialization
            vmstop     the VM is about to shutdown
            load       a new class has been loaded
            unload     a classloader has been unloaded
            throw      a Java exception has been thrown
            catch      a Java exception has been caught
            uncaught   a Java exception was not handled by the application
            thrstart    a new thread has started
            thrstop    an old thread has stopped
            blocked    a thread is blocked entering a monitor
            fullgc      garbage collection has started
            

从 TITLE 信息块,我们只能初步了解问题产生的原因,如果要进一步了解问题的详细信息,还要查看 GPINFO 信息块(清单 7):


清单7. GPINFO 信息块
NULL           ----------------------------------------------
            0SECTION       GPINFO subcomponent dump routine
            NULL           ================================
            2XHOSLEVEL     OS Level         : Windows XP 5.1 build 2600 Service Pack 3
            2XHCPUS        Processors -
            3XHCPUARCH       Architecture   : x86
            3XHNUMCPUS       How Many       : 2
            NULL
            1XHEXCPCODE    J9Generic_Signal_Number: 00000004
            1XHEXCPCODE    ExceptionCode: C0000005
            1XHEXCPCODE    ExceptionAddress: 412E136E
            1XHEXCPCODE    ContextFlags: 0001003F
            1XHEXCPCODE    Handler1: 7EFB04E0
            1XHEXCPCODE    Handler2: 7F057A80
            1XHEXCPCODE    InaccessibleAddress: CCCCCCCC
            NULL
            1XHEXCPMODULE  Module:
            C:\eclipse\workspace\Serviceability\TestApps\SampleLeak\TestJin\CallJni.dll
            1XHEXCPMODULE  Module_base_address: 412D0000
            1XHEXCPMODULE  Offset_in_DLL: 0001136E
            NULL
            1XHFLAGS       VM flags:00040000
            NULL
            

GPINFO 信息块中我们可以找到问题的异常代码,ExceptionCode: C0000005 代表内存访问错误或者非法的内存操作。Module: C:\eclipse\workspace\Serviceability\TestApps\TestJin\CallJni.dll 指明了发生问题的原生模块。 CallJni.dll 这个动态连接库是我们自己的 JNI 代码,因此很容易发现问题的所在。在一个复杂的 java 运行环境下,很多时候异常是在第三方的代码库中产生的,我们没有办法查看源代码中的问题,这时候只能通过文件名中的一些关键字来推测问题发生的位置,这些关键字包括(清单 8):


清单 8. 需要注意的关键字
GC = garbage collection/collector (how Java frees memory)
            JIT = just-in-time compiler, a feature of JVM
            JDBC = Java feature for database access
            ORB = object request broker, lower layer of app server
            JMS = java messaging service, feature of web server or add-on
            

例如,Module: C:\JDK\IBM\java1.5.0\jre\bin\j9jit23.dll

说明 JIT 模块发生问题,用户可以使用 JITC_COMPILEOPT 变量的 SKIP 选项禁用对当前方法进行 JIT 编译,然后再对系统的运行情况进行进一步的跟踪。

JITC_COMPILEOPT=SKIP{failingPackage/failingClass}{failingMethod}

除此之外,查看 THREADS 信息块中当前线程的执行堆栈也有助于我们对问题的诊断。从清单 9 我们可以看到 main 线程在执行 CallJni.doSomeThing 方法数的过程中发生了问题,据此我们可以返回源代码中查找相应的方法,进而确定问题的根源。


清单 9. Threads 信息块
NULL           ----------------------------------------------------
            0SECTION       THREADS subcomponent dump routine
            NULL           =================================
            NULL
            1XMCURTHDINFO  Current Thread Details
            NULL           ----------------------
            3XMTHREADINFO  "main" (TID:0x408C7C00, sys_thread_t:0x00366278, state:R,
            native ID:0x000016CC) prio=5
            4XESTACKTRACE          at test/CallJni.doSomeThing(Native Method)
            4XESTACKTRACE          at test/TestJin.work(TestJin.java:16)
            4XESTACKTRACE          at test/TestJin.main(TestJin.java:11)
            NULL
            

诊断 CPU 利用率过高问题

CPU 使用率过高可能是由于某些线程陷入了死循环或者执行了不适当的操作引起的,其诊断方法就是将这些线程找出来,修正问题或者进行代码优化。由于 Java Dump 中并没有包含各线程的资源使用情况,因此我们需要结合其他的操作系统命令/工具(prstat、top、pslist 等等),将 CPU 使用率较高的线程映射到 Java Dump 中,并分析这些线程的状态以及可能发生的问题。

从下面这段 PSList 的输出结果中我们可以看到 jvm 内部每个线程消耗的总的“用户时间”和“内核时间”,比较几次 PSList 的输出结果,我们就能从中找出那些 CPU 使用时间显著增加的线程,再将这些线程的 TID 映射到Java Dump中,进而查看问题线程的详细信息。


清单 10. PSList 的输出结果
pslist -d <Java PID>
            Tid Pri    Cswtch            State     User Time   Kernel Time   Elapsed Time
            2908   8      2025   Wait:Executive  0:00:00.359   0:00:01.312    1:48:08.046
            4344  15       157     Wait:UserReq  0:00:00.218   0:00:00.015    1:48:07.921
            4836  15    415456     Wait:UserReq  0:00:00.000   0:00:00.000    1:48:07.921
            2496   8         1     Wait:UserReq  0:00:00.000   0:00:00.000    1:48:07.796
            4648   9         1     Wait:UserReq  0:00:00.000   0:00:00.000    1:48:07.796
            3116   9         7     Wait:UserReq  0:00:00.000   0:00:00.000    1:48:07.796
            5268   8       189     Wait:UserReq  0:00:00.015   0:00:00.000    1:48:07.796
            5220   7   6991523          Running  1:47:42.031   0:00:01.218    1:48:05.593
            3932   9         2     Wait:UserReq  0:00:00.000   0:00:00.000    1:48:05.125
            

与线程死锁问题不同,在分析 CPU 利用率过高的问题时,我们不需要关心那些处于等待状态的线程,因为线程处于等待状态不需要消耗 CPU 资源。我们关注的重点应该是 THREADS 信息块中那些正在运行(state:R 状态)的线程。很多时候为了分析线程状态的一些变化,我们需要对比多个 Java Dump 文件,看哪些线程状态发生了变化,哪些一直在执行相同的函数,从而找出那些可疑的问题线程。

诊断堆内存不足问题

除了 Thread 相关的信息外,Java Dump 还包含 Memory 和 GC 等方面的信息,虽然这些信息不像 Heap Dump 和 VerboseGC 那么详细,但对于一些比较简单的问题定位还是很有帮助的。例如,下面的 Java dump 清单中,Dump Event "uncaught" (00008000) Detail "java/lang/OutOfMemoryError" received 告诉我们问题是由于内存溢出引起的,并且从 MEMINFO 信息块中可以找到当前堆中的空间使用情况, 1ffa0 的剩余空间说明系统的可用堆内存已经严重不足了,需要我们扩大堆内存的大小或者修改应用程序使其占用更少的内存。


清单 11. MEMINFO 信息块
NULL         ----------------------------------------------------
            0SECTION     TITLE subcomponent dump routine
            NULL         ===============================
            1TISIGINFO  Dump Event "uncaught" (00008000) Detail "java/lang/OutOfMemoryError" received
            1TIDATETIME  Date:                 2008/04/20 at 19:13:50
            1TIFILENAME  Javacore filename:
            c:\Serviceability\AppServer\profiles\AppSrv01\javacore.20080420.185326.948.txt
            NULL           ----------------------------------------------------
            0SECTION       MEMINFO subcomponent dump routine
            NULL           =================================
            1STHEAPFREE    Bytes of Heap Space Free: 1ffa0
            1STHEAPALLOC   Bytes of Heap Space Allocated: 40000000
            

类加载问题

常见的类加载问题包括: ClassNotFoundException,Jar 包冲突以及由类装入引发的其他问题(例如 jdk 1.4 中的内存碎片问题) Java Dump 文件的 Classes 信息块的格式如清单中示,这些信息可以帮我们确定以下问题:

  • 当前系统中有哪些 Class 文件被加载进来。
  • 确认某个 Class 是否被正确的 ClassLoader 所加载,即不同的 ClassLoader 之间是否有 Jar 包冲突。
  • 已经加载的 Class 的个数。在IBM Jre1.4中,我们可以参考系统中 Class 的个数来设置 KCluster 的大小。

清单 12. CLASSES 信息块
NULL     ---------------------------------------------------------
            0SECTION       CLASSES subcomponent dump routine
            NULL           =================================
            1CLTEXTCLLOS       Classloader summaries
            1CLTEXTCLLSS           12345678:
            1=primordial,2=extension,3=shareable,4=middleware,5=system,
            6=trusted,7=application,8=delegating
            2CLTEXTCLLOADER        p---st-- Loader *System*(0x008DA0B0)
            3CLNMBRLOADEDLIB        Number of loaded libraries 3
            3CLNMBRLOADEDCL            Number of loaded classes 347
            2CLTEXTCLLOADER        -x--st-- Loader sun/misc/Launcher$ExtClassLoader(0x008E5E38),
            Parent *none*(0x00000000)
            3CLNMBRLOADEDLIB        Number of loaded libraries 0
            3CLNMBRLOADEDCL            Number of loaded classes 0
            2CLTEXTCLLOADER        -----ta- Loader sun/misc/Launcher$AppClassLoader(0x008EF3E0),
            Parentsun/misc/Launcher$ExtClassLoader(0x008E5E38)
            3CLNMBRLOADEDLIB        Number of loaded libraries 0
            3CLNMBRLOADEDCL            Number of loaded classes 2
            1CLTEXTCLLIB       ClassLoader loaded libraries
            2CLTEXTCLLIB          Loader *System*(0x008DA0B0)
            3CLTEXTLIB               C:\JDK\IBM\java1.5.0\jre\bin\java
            3CLTEXTLIB               C:\JDK\IBM\java1.5.0\jre\bin\jclscar_23
            3CLTEXTLIB               C:\JDK\IBM\java1.5.0\jre\bin\zip
            1CLTEXTCLLOD       ClassLoader loaded classes
            2CLTEXTCLLOAD          Loader *System*(0x008DA0B0)
            3CLTEXTCLASS               java/io/ByteArrayOutputStream(0x40D40098)
            3CLTEXTCLASS               sun/nio/ByteBuffered(0x40D40330)
            3CLTEXTCLASS               java/lang/ref/PhantomReference(0x40DB9360)
            3CLTEXTCLASS               sun/misc/Cleaner(0x40DB94A8)
            





回页首


常见问题

关于 Java dump,下面是一些有可能让你产生困惑的问题:

为什么发生 JVM Crash 时,JVM 没有自动生成 Java dump 文件?

答:这种情况大多与系统的环境变量或者 JVM 启动参数的设置有关,比如设置了 DISABLE_JAVADUMP=true,IBM_NOSIGHANDLER=true 等等,因此可以首先检查系统设置和 JVM 启动参数。当然也不排除因为一些不确定因素导致 JVM 无法产生 Java dump,虽然这种可能性比较小。

JVM 在生成 Java dump 的同时也生成了 Heap dump,它们之间有没有什么联系?

答:有,但是关系不大。因为 java dump 主要反映的是线程的运行状态,而 Heap dump 则主要反映对象之间的引用关系,所以两者之间没有太大的联系。有时候我们可以通过锁对象或者 Class 对象的起始地址找到它在 Heap dump 中的位置,但大多数时候这对故障诊断并没有多大意义。

为什么有些 java dump 的锁没有 owner?

答:并不是所有的锁都被其它线程持有,有些锁是用作主动等待的,比如 sleep() ,wait(),join() 等,这些锁并没有被其它线程占用,被它阻塞的线程只是在等待通知,即 “Waiting to be notified”。从线程状态上看,这些锁一般都处于 “CW” 状态。

Java Dump 中的很多线程处于 state:CW 和 state:B 状态,它们之间有何区别?

答:两者都处于等待状态。不同是:

CW - Condition Wait – 条件等待. 这种等待一般是线程主动等待或者正在进行某种 IO 操作,而并非等待其它线程释放资源。比如 sleep() ,wait(),join() 等方法的调用。

B – Blocked – 线程被阻塞,与条件等待不同,线程被阻塞一般不是线程主动进行的,而是由于当前线程需要的资源正在被其他线程占用,因此不得不等待资源释放以后才能继续执行,例如 synchronized 代码块。

为什么我在 PsList 里看到的线程无法映射到 Java dump 中?

答:由于很多操作系统工具和命令输出的线程的 TID 都是十进制的,映射到 Java dump 时首先要将其转换为十六进制数字,然后再到 Java dump 中查找对应的 native ID。Java dump 中每个线程都有两个ID, 一个是 java 线程的TID, 另一个是对应操作系统线程的 native ID。

阅读 Websphere Appliaction Server 产生的 Java dump 文件有没有什么特别的技巧?

答:对于 WAS 应用程序来说,线程信息往往要比一般的应用程序复杂的多。记住一些常见的 ThreadName 可以帮助我们更好的理解应用程序的运行状态,例如:

线程名 线程信息
Web Container: # WAS web container *
Alarm Thread # handles timer processing
Session.Transports.Threads:### servlet threads for processing HTTP requests
ORB.thread.pool:### ORB thread (ORB data)
P=437206:O=0:
StandardRT=19027:LocalPort=9001:RemoteHost=hostname.ibm.com:RemoteP
an ORB thread for receiving an EJB request or other ORB request
Thread-## JVM thread (default name)





回页首


结束语

本文比较全面的介绍了 Java dump 在 JVM 故障诊断过程中的作用。正像你所看到的,Java dump 文件主要帮我们解决与线程相关的各种问题,但同时它还为我们提供了很多其它有用的信息(比如 JVM Crash),在某些情况下,这些信息对于我们至关重要,所以充分的利用 Java dump 文件可以帮我们更快的找到解决问题的方向。



参考资料

学习

获得产品和技术

posted @ 2010-02-01 10:38 希 阅读(1170) | 评论 (0)编辑 收藏

中新网杭州 (记者 汪恩民 实习生 沈兰)长江后浪推前浪,江山代有才人出。面对台下有志创业的“后浪”们,网易CEO丁磊今天在“杭州大学生创业联盟成立仪式”上“抛”出“自信、坚持、认真、包容”八字箴言。

特别顾问:创业的路上遍布着挫折

“回想我的创业之路,我当年很幸运。”作为杭州大学生创业联盟特别顾问,丁磊很庆幸在年轻的时候可以做自己喜欢的事情。“创业是一个很热门的词。但是,我要提醒大家一件事,创业的路上遍布着挫折。”

对于自己抛出的八字箴言,丁磊为创业者作了详细的解释。“首先,你必须要自信。如果对自己做的事情都没有信心,那么你将很难获得成功。有自信你不一定能获得成功,但没有自信你一定不会成功。其次,你必须要学会坚持。我已经说过,创业的路上会有很多挫折,每一个成功的人都要经历挫折的考验。这个过程中就需要坚持。另外,你还需要认真。也就是说,你要学会踏踏实实做事情。最后,你还要学会包容。认真是对自己的要求,包容则是对别人的。包容就是要我们能够宽恕别人的错误。”

丁磊在最后强调了一点:“大学生创业要无时无刻保持一颗谦虚求知的心。”

创业导师:时间是属于年轻人的

创业导师代表田宁表示,时间是属于年轻人的。“60后可以分到房子,70后可以分到工作,那么我们这些80后和90后呢?我们要靠自己的双手创造一切。很多IT业的巨头,你可以去查他们的发家史,很多都是大学生。”

田宁称,这一代人是幸福的。“我们失去很多的同时,也获得了很多。当60后和70后小时候只能玩泥土的时候,我们小时候就可以玩电脑了。”

“对于大学生创业,他们需要得到前辈们的指导。”田宁表示,创业导师应该把自己痛苦的创业经历告诉他们。

轮值主席:创业群体需要“转型升级”

“16年前,我来到杭州开始创业。那时候的情况跟今天比较,真是今非昔比。”杭州大学生创业联盟轮值主席林东表示,那时候的创业主流群体还不是大学生。“然而,他们依然撑起了现在的经济发展。”

林东称,现在需要的不仅是技术的转型升级,还需要创业群体的转型升级。“在十年以后,现在一些黑心商人的形象就很少看到了,更多的是李开复这样的商人。”

“创业充满了风险。”林东表示,创业导师的成长离不开社会的支持,大家有义务和责任帮助“小朋友们”创业。“有我们大家一起的努力,我相信一定会取得更大的辉煌。”

杭州市长:大学生创业应永不言败

“大学生创业应该永不言败!”杭州市长蔡奇表示,创业带动就业,应该形成杭州的一面旗帜。“杭州应该坚持人才强市战略,抓住大学生创业为杭州积蓄力量,为天堂硅谷积蓄续力量。千万不要小看大学生今天创业的弱小和落魄,通过他们能看到杭州的明天。”

 

记者了解到,杭州大学生创业联盟是根据杭州市委市政府提出“以创业带动就业”的工作部署,成立服务大学生创业工作社团组织。创新工场董事长兼CEO李开复、阿里巴巴集团董事局主席兼CEO马云、网易CEO丁磊、赛伯乐(中国)投资董事长朱敏加盟杭州大学生创业联盟出任特别顾问。

蔡奇称,杭州大学生创业联盟有三个特点。“首先,它是创业大学生集聚的组织。所有愿意创业的大学生,都可以从那里得到帮助。其次,它是整合资源的创业中心。特别值得一提的,是创业投资基金也加入了这个组织里。最后,大学生创业联盟是个非政府机构。只靠政府是不够的,我们需要更多非政府组织参与,来做政府做不到的事情。”

posted @ 2009-12-22 14:02 希 阅读(254) | 评论 (0)编辑 收藏

刚看蜗居第一集我就忍不住哭了,海平告诉海藻“现在是工作挑人不是人挑工作。。。。。”想起了自己当时找工作,好像也是一样的,但是知道自己被录用了心理的欢喜。。。。。我觉得现在80后 90后的人和他们的家长都改看看,看看海平复旦毕业,结果呢。。。前两天有个同学给我打电话说她和她的男友在北京过的非常的难,告诉我他们为了生活的种种争吵。

posted @ 2009-11-27 13:33 希 阅读(309) | 评论 (0)编辑 收藏

如何更改Web.Config里默认的编码设置及其对于单个aspx页面的编码格式的设置

把全球化设置改成这样会省下很多事!

<globalization fileEncoding="GB2312" requestEncoding="GB2312" responseEncoding="GB2312"/>

这样一来,使用Request.QueryString[""]的时候就不用手动检索编码并解码了!省事啊!

在Web.Config中设置单个aspx页面的编码格式

   <location path="Member/MyShortMessage.aspx">
     <system.web>
       <globalization requestEncoding="utf-8" responseEncoding="utf-8"/>
     </system.web>
   </location>

posted @ 2009-08-05 14:49 希 阅读(854) | 评论 (0)编辑 收藏

 
 

本内容源自于老邢这8年来的电子商务从业经验、派代网的运营体会及与众多电子商务相关人士交流综合整理而得。其中,这8年重点涉足了B2C、C2C和B2B,同时,还有社区的建设、运营和UI/UE等。

本内容纯粹是个人观点,必然有偏颇之处,看官仁者见仁,还望多多指正。

 

第一部分 B2C的本质

1 B2C本质上就是零售业,所以,要做大,现金流是命根子。
2、规模是零售企业撬动上下游资源的核心法宝之一,B2C也不例外;
3、B2C要上规模,就必须要标准化管理,如把人干的事情部分或全部交给机器(即程序)去做。
4、网上零售和传统零售的核心区别:售前更近80米(即用户没购物之前,能知道用户的购物偏好,这个需要很强的技术作为支撑);
 
第二部分 用户体验
5、眼前,中国的B2C普遍不够重视网站的UIUE等,其重要性理同于超市的货架及商品摆设等;
6、全备库是提高用户购物体验的核心办法之一,即别指望在中国靠虚库也能做大(这个是阶段性问题,初期虚库或部分虚库是很务实和需要的的);
7、物流已是中国B2C高速发展的金箍圈(其背后还连带着资金流),也是影响购物体验的障碍之一;
 
第三部分 市场和运营
8、中国B2C和美国B2C最大的区别:美国是走在高速路上,而中国是土路+高速路;
9、中国不是一个市场,是由N多个消费观念差异巨大的市场组成;
10、网购人群是个崭新的消费群体,切勿用其他传统的消费观念去套,这好比用70看不懂90一样;
11、中国B2C仍然处于推广年代,远谈不上营销及品牌管理;
12、在中国电商界,低价是个杀手锏,也是个双刃剑,但切勿忽略消费者对好价格无好服务的疲倦;
13、仅重电子,或仅重商务B2C公司要做大的概率不大,但是,可以成为一个养家糊口的生意;
14、意识和体制是传统渠道进入电子商务最大的障碍,其背后是勇气和利益分割等;
 
第四部分 未来猜测
15、淘宝成就了中国的网购,也将成就中国的B2C,但未必能成就自己;
16、中国出现amazon的概率近乎为零;要有,所花的时间和金钱将是amazon的倍级;  
17、中国B2C的机会,属于那些重视且具有营销、技术和管理能力的企业;
18、中国B2C已经上了高速发展的快车道,且这种高速度将维持约5年左右;
19B2C已逐步呈现出类似传统零售的业态,有全国性的大连锁、区域连锁和小区便利店;
20、中国电子商务未来的主流,不属于B2B,也不属于C2C,而必然属于B2C

posted @ 2009-07-26 16:08 希 阅读(360) | 评论 (0)编辑 收藏

new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0))

posted @ 2009-07-22 17:38 希 阅读(250) | 评论 (0)编辑 收藏

GridBagConstraints(int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, int anchor, int fill, Insets insets, int ipadx, int ipady)
组件的位置 第gridx行 第gridy列 此组件占gridwidth行单元格,占gridheight列单元格,weightx,weighty剩余单元格的 anchor当组件小于其显示区域时使用此字段

posted @ 2009-07-22 13:45 希 阅读(321) | 评论 (0)编辑 收藏

类java.awt.SystemTray代表了桌面的系统托盘.你可以通过静态方法SystemTray.getSystemTray()来进行访问.但是,在这之前,你的程序应该用静态方法SystemTray.isSupported()来测试一下系统是否支持托盘.如果系统托盘不存在或者系统不支持托盘,isSupported()将返回flase.在这种情况下调用getSysemTray的话,它将抛出java.lang.UnsupportedOperationException.
每个java应用程序都只有一个单一的SystemTray实例.所以,一个程序不能创建只属于它自己的SystemTray实例;而它必须用getSystemTray()方法来取得已有的那个.
SystemTray包含有一个或多个TrayIcon.通过SystemTray的方法add(java.awt.TrayIcon)方法可以添加一个TrayIcon到托盘,通过remove(java.awt.TrayIcon)将一个TrayIcon从托盘移除.注意最近添加的测试代码指明,如操作系统或者Java runtime不添加TrayIcon到托盘,add()方法可能会抛出AWTException.例如,在X-Windows中,如果托盘不存在,它将抛出AWTException
下面的代码演示了如果访问系统托盘:
final TrayIcon trayIcon;

if (SystemTray.isSupported()) {

    SystemTray tray 
= SystemTray.getSystemTray();
    Image image 
= Toolkit.getDefaultToolkit().getImage("tray.gif");

    MouseListener mouseListener 
= new MouseListener() {             
        
public void mouseClicked(MouseEvent e) {
            System.out.println(
"Tray Icon - Mouse clicked!");                 
        }
        
public void mouseEntered(MouseEvent e) {
            System.out.println(
"Tray Icon - Mouse entered!");                 
        }
        
public void mouseExited(MouseEvent e) {
            System.out.println(
"Tray Icon - Mouse exited!");                 
        }
        
public void mousePressed(MouseEvent e) {
            System.out.println(
"Tray Icon - Mouse pressed!");                 
        }
        
public void mouseReleased(MouseEvent e) {
            System.out.println(
"Tray Icon - Mouse released!");                 
        }
    };

    ActionListener exitListener 
= new ActionListener() {
        
public void actionPerformed(ActionEvent e) {
            System.out.println(
"Exiting...");
            System.exit(
0);
        }
    };    
    
    PopupMenu popup 
= new PopupMenu();
    MenuItem defaultItem 
= new MenuItem("Exit");
    defaultItem.addActionListener(exitListener);
    popup.add(defaultItem);

    trayIcon 
= new TrayIcon(image, "Tray Demo", popup);

    ActionListener actionListener 
= new ActionListener() {
        
public void actionPerformed(ActionEvent e) {
            trayIcon.displayMessage(
"Action Event"
                
"An Action Event Has Been Peformed!",
                TrayIcon.MessageType.INFO);
        }
    }; 
         
    trayIcon.setImageAutoSize(
true);
    trayIcon.addActionListener(actionListener);
    trayIcon.addMouseListener(mouseListener);

    
try {
        tray.add(trayIcon);
    } 
catch (AWTException e) {
        System.err.println(
"TrayIcon could not be added.");
    }

else {

    
//  不支持系统托盘

}
实现Tray Icon
系统托盘允许一个或多个java.awt.TrayIcon添加到它或从它移除:一个TrayIcon对象代表着一个可以添加到系统托盘的托盘图标.但是,TrayIcon的功能不止是一个显示在托盘里的图标.它还可以有工具提示(tooltip),有一个AWT的弹出菜单,还有一系列相关的侦听器
 一个TrayIcon会产生各种各样的MouseEvent(pressed,released,和clicked).可以对它添加相关的侦听器去接收这些事件的通知.但是要注意,在MouseEvent从TrayIcon接收到的坐标是相对于屏幕而不是TrayIcon它自己的.TrayIcon它自己处理这些事件.例如,默认情况下,当右击TrayIcon时,和它相关的弹出菜单就会显示.当鼠标在它上面停留时,工具提示就会出现.TrayIcon也可以产生ActionEvent.在一些平台上,ActionEvent产生于用户通过鼠标或键盘选择该TrayIcon时.一个实现良好的TrayIcon应该用不同的方法去显示弹出菜单和选择托盘图标.
注意,根据最新的javadocs,当一个鼠标事件被发送到它的侦听器时,它的component属性(通过父类ComponentEvent.getComponent()获取)将会被设置为null.而source属性(通过EventObject.getSource()获取)将被设置为该TrayIcon
有用的特点
用setImage()方法可以在以后更新TrayIcon的图标:
     trayIcon.setImage(updatedImage);
同样你可以更新工具提示:
     trayIcon.setTooltip("I'm busy. Go away.");
TrayIcon有一个非常有用的自动调整大小的属性.这个属性决定是否自动调整图片的大小以适应托盘的大小.默认这个属性是false的.如果图片的大小不适合托盘的大小,图片仍会以它原来的大小绘制到托盘上.也就是说,如果图片比分配的托盘空间大,图片将被剪切.另一方面,如果自动调整大小被设为true,那么图片将伸缩以适应托盘图标的大小
     trayIcon.setImageAutoSize(true);
最后,如果你想偶尔用工具提示通知用户程序的一些变化,你可以用displayMessage()方法.这个方法弹出一个在托盘图标上弹出一个消息.这个消息会在一段时间之后,或者用户单击它之后消失.单击它的时候,根据系统的情况,会产生ActionEvent
     trayIcon.displayMessage("Finished downloading",
           "Your Java application has finished downloading",
           TrayIcon.MessageType.INFO);
第一个参数是标题.它通常在弹出消息里会以粗体显示.第二个参数是要显示的消息.最后,最后一个参数是TrayIcon的一个枚举类型TrayIcon.Message,有四个选择.这些选项可以用作决定在显示消息时,是否应执行某些图形操作或其他系统动作.四个选择如下:
TrayIcon.MessageType.ERROR   An error message
TrayIcon.MessageType.INFO   An information message
TrayIcon.MessageType.NONE   A simple message
TrayIcon.MessageType.WARNING   A warning message
===================================================
下面是我自己写的例子
 
package blog.swing;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.awt.PopupMenu;
import java.awt.MenuItem;
import java.awt.Image;
import java.awt.AWTException;
import java.awt.Toolkit;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.text.SimpleDateFormat;
import java.util.Calendar;

class SystemTrayDemo 
{
    SystemTray systemTray;
    TrayIcon trayIcon;
    Image trayImage;
    String trayTip;
    PopupMenu trayPopupMenu;
    MenuItem trayMenuItem;
    ActionListener trayActionListener;
    ActionListener menuActionListener;
    MouseListener trayMouseListener;
    Thread displayTime;
    
public SystemTrayDemo() {
        
if( SystemTray.isSupported() ){
            trayMouseListener 
= new MouseListener() {             
                
public void mouseClicked(MouseEvent e) {
                    System.out.println(
"Tray Icon - Mouse clicked!");                 
                }
                
public void mouseEntered(MouseEvent e) {
                    System.out.println(
"Tray Icon - Mouse entered!");                 
                }
                
public void mouseExited(MouseEvent e) {
                    System.out.println(
"Tray Icon - Mouse exited!");                 
                }
                
public void mousePressed(MouseEvent e) {
                    System.out.println(
"Tray Icon - Mouse pressed!");                 
                }
                
public void mouseReleased(MouseEvent e) {
                    System.out.println(
"Tray Icon - Mouse released!");                 
                }
            };
            trayActionListener 
= new ActionListener(){
                
public void actionPerformed( ActionEvent e ){
                    System.out.println( 
"Tray Icon - Action event happened!" );;
                }
            }; 
            menuActionListener 
= new ActionListener(){
                
public void actionPerformed( ActionEvent e ){
                    System.exit(
0);
                }
            };
            trayPopupMenu 
= new PopupMenu();
            trayMenuItem 
= new MenuItem("exit");
            trayMenuItem.addActionListener( menuActionListener );
            trayPopupMenu.add( trayMenuItem );
            trayTip 
= "This is a SystemTray Demo";
            trayImage 
= Toolkit.getDefaultToolkit().getImage("images/leaf.gif");
            trayIcon 
= new TrayIcon( trayImage,trayTip,trayPopupMenu );
            trayIcon.addActionListener( trayActionListener );
            trayIcon.addMouseListener( trayMouseListener );
            trayIcon.setImageAutoSize( 
true );
            systemTray 
= SystemTray.getSystemTray();
            
try{
                systemTray.add( trayIcon );
            }
catch( AWTException e ){
                e.printStackTrace();
            }
        }
else{
            System.out.println( 
"SystemTray unsupported!" );
        }
        displayTime 
= new Thread(new Runnable(){
            
public void run(){
                Calendar now;
                SimpleDateFormat sdf 
= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                String time;
                
while(true){
                    now 
= Calendar.getInstance();                    
                    time
= sdf.format( now.getTime() );
                    trayIcon.displayMessage(
"报时",time,TrayIcon.MessageType.INFO);
                    
try{
                        Thread.sleep(
60000);
                    }
catch( InterruptedException e ){
                        e.printStackTrace();
                    }
                }
            }
        });
        displayTime.start();
    }
    
public static void main(String[] args) 
    {
        
new SystemTrayDemo();
    }
}

posted @ 2009-07-07 22:01 希 阅读(974) | 评论 (0)编辑 收藏

在struts-config。xml文件中在<forword>中加入redirect="true"  contextRelative="false"即可在当前相对路径下

posted @ 2009-06-17 17:39 希 阅读(216) | 评论 (0)编辑 收藏

严重: Servlet.service() for servlet action threw exception
java.lang.NullPointerException
 at org.hibernate.tuple.AbstractEntityTuplizer.createProxy(AbstractEntityTuplizer.java:372)
 at org.hibernate.persister.entity.AbstractEntityPersister.createProxy(AbstractEntityPersister.java:3121)
 at org.hibernate.event.def.DefaultLoadEventListener.createProxyIfNecessary(DefaultLoadEventListener.java:232)
 at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:173)
 at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:87)
 at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:862)
 at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:830)
 at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:266)
 at org.hibernate.type.EntityType.resolve(EntityType.java:303)
 at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:116)
 at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:842)
 at org.hibernate.loader.Loader.doQuery(Loader.java:717)
 at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
 at org.hibernate.loader.Loader.doList(Loader.java:2145)
 at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2029)
 at org.hibernate.loader.Loader.list(Loader.java:2024)
 at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:375)
 at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:308)
 at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:153)
 at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1106)
 at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
 at org.springframework.orm.hibernate3.HibernateTemplate$29.doInHibernate(HibernateTemplate.java:849)
 at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:372)
 at org.springframework.orm.hibernate3.HibernateTemplate.find(HibernateTemplate.java:840)
 at org.springframework.orm.hibernate3.HibernateTemplate.find(HibernateTemplate.java:832)
 at dao.daoImlHibernate.WordDaoImplHibernate.listAll(WordDaoImplHibernate.java:36)
 at service.serviceImpl.WordServiceImpl.listAll(WordServiceImpl.java:24)
 at com.yourcompany.struts.action.WordAction.listAll(WordAction.java:45)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
 at java.lang.reflect.Method.invoke(Unknown Source)
 at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:270)
 at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:187)
 at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431)
 at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236)
 at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
 at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:414)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:228)
 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:216)
 at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
 at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:634)
 at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:445)
 at java.lang.Thread.run(Unknown Source)


解决方法在从表中 <many-to-one name="usrs" class="model.Usrs" fetch="select" lazy="false">将lazy=“false”
            <column name="usr_id" />
        </many-to-one>

posted @ 2009-06-17 17:35 希 阅读(379) | 评论 (0)编辑 收藏


posts - 40, comments - 9, trackbacks - 0, articles - 9

Copyright © 希