2010年2月1日

          文檔選項
          將打印機的版面設置成橫向打印模式

          打印本頁

          將此頁作為電子郵件發送

          將此頁作為電子郵件發送

          未顯示需要 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 希 閱讀(1210) | 評論 (0)編輯 收藏


          2009年12月22日

          中新網杭州 (記者 汪恩民 實習生 沈蘭)長江后浪推前浪,江山代有才人出。面對臺下有志創業的“后浪”們,網易CEO丁磊今天在“杭州大學生創業聯盟成立儀式”上“拋”出“自信、堅持、認真、包容”八字箴言。

          特別顧問:創業的路上遍布著挫折

          “回想我的創業之路,我當年很幸運。”作為杭州大學生創業聯盟特別顧問,丁磊很慶幸在年輕的時候可以做自己喜歡的事情。“創業是一個很熱門的詞。但是,我要提醒大家一件事,創業的路上遍布著挫折。”

          對于自己拋出的八字箴言,丁磊為創業者作了詳細的解釋。“首先,你必須要自信。如果對自己做的事情都沒有信心,那么你將很難獲得成功。有自信你不一定能獲得成功,但沒有自信你一定不會成功。其次,你必須要學會堅持。我已經說過,創業的路上會有很多挫折,每一個成功的人都要經歷挫折的考驗。這個過程中就需要堅持。另外,你還需要認真。也就是說,你要學會踏踏實實做事情。最后,你還要學會包容。認真是對自己的要求,包容則是對別人的。包容就是要我們能夠寬恕別人的錯誤。”

          丁磊在最后強調了一點:“大學生創業要無時無刻保持一顆謙虛求知的心。”

          創業導師:時間是屬于年輕人的

          創業導師代表田寧表示,時間是屬于年輕人的。“60后可以分到房子,70后可以分到工作,那么我們這些80后和90后呢?我們要靠自己的雙手創造一切。很多IT業的巨頭,你可以去查他們的發家史,很多都是大學生。”

          田寧稱,這一代人是幸福的。“我們失去很多的同時,也獲得了很多。當60后和70后小時候只能玩泥土的時候,我們小時候就可以玩電腦了。”

          “對于大學生創業,他們需要得到前輩們的指導。”田寧表示,創業導師應該把自己痛苦的創業經歷告訴他們。

          輪值主席:創業群體需要“轉型升級”

          “16年前,我來到杭州開始創業。那時候的情況跟今天比較,真是今非昔比。”杭州大學生創業聯盟輪值主席林東表示,那時候的創業主流群體還不是大學生。“然而,他們依然撐起了現在的經濟發展。”

          林東稱,現在需要的不僅是技術的轉型升級,還需要創業群體的轉型升級。“在十年以后,現在一些黑心商人的形象就很少看到了,更多的是李開復這樣的商人。”

          “創業充滿了風險。”林東表示,創業導師的成長離不開社會的支持,大家有義務和責任幫助“小朋友們”創業。“有我們大家一起的努力,我相信一定會取得更大的輝煌。”

          杭州市長:大學生創業應永不言敗

          “大學生創業應該永不言敗!”杭州市長蔡奇表示,創業帶動就業,應該形成杭州的一面旗幟。“杭州應該堅持人才強市戰略,抓住大學生創業為杭州積蓄力量,為天堂硅谷積蓄續力量。千萬不要小看大學生今天創業的弱小和落魄,通過他們能看到杭州的明天。”

           

          記者了解到,杭州大學生創業聯盟是根據杭州市委市政府提出“以創業帶動就業”的工作部署,成立服務大學生創業工作社團組織。創新工場董事長兼CEO李開復、阿里巴巴集團董事局主席兼CEO馬云、網易CEO丁磊、賽伯樂(中國)投資董事長朱敏加盟杭州大學生創業聯盟出任特別顧問。

          蔡奇稱,杭州大學生創業聯盟有三個特點。“首先,它是創業大學生集聚的組織。所有愿意創業的大學生,都可以從那里得到幫助。其次,它是整合資源的創業中心。特別值得一提的,是創業投資基金也加入了這個組織里。最后,大學生創業聯盟是個非政府機構。只靠政府是不夠的,我們需要更多非政府組織參與,來做政府做不到的事情。”

          posted @ 2009-12-22 14:02 希 閱讀(266) | 評論 (0)編輯 收藏


          2009年11月27日

          剛看蝸居第一集我就忍不住哭了,海平告訴海藻“現在是工作挑人不是人挑工作。。。。。”想起了自己當時找工作,好像也是一樣的,但是知道自己被錄用了心理的歡喜。。。。。我覺得現在80后 90后的人和他們的家長都改看看,看看海平復旦畢業,結果呢。。。前兩天有個同學給我打電話說她和她的男友在北京過的非常的難,告訴我他們為了生活的種種爭吵。

          posted @ 2009-11-27 13:33 希 閱讀(312) | 評論 (0)編輯 收藏


          2009年8月5日

          如何更改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 希 閱讀(873) | 評論 (0)編輯 收藏


          2009年7月26日

           
           

          本內容源自于老邢這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 希 閱讀(369) | 評論 (0)編輯 收藏


          2009年7月22日

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

          posted @ 2009-07-22 17:38 希 閱讀(258) | 評論 (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 希 閱讀(329) | 評論 (0)編輯 收藏


          2009年7月7日

          類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 希 閱讀(983) | 評論 (0)編輯 收藏


          2009年6月17日

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

          posted @ 2009-06-17 17:39 希 閱讀(219) | 評論 (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 希 閱讀(391) | 評論 (0)編輯 收藏


          僅列出標題  下一頁

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

          Copyright © 希

          主站蜘蛛池模板: 曲周县| 邯郸市| 岗巴县| 德惠市| 揭东县| 辉县市| 大同市| 怀化市| 昌乐县| 永宁县| 泌阳县| 雅江县| 黎川县| 六安市| 大埔区| 右玉县| 灵璧县| 余姚市| 大田县| 麻城市| 慈利县| 江陵县| 太仓市| 乌恰县| 堆龙德庆县| 庆安县| 辽宁省| 道真| 江津市| 抚州市| 旬阳县| 巴东县| 哈尔滨市| 孟连| 老河口市| 平利县| 稷山县| 武穴市| 湄潭县| 青河县| 甘南县|