2009-12-09 87 views
0

這是我對S.O.的第一個問題。
我有一個很奇怪的問題。
下面是我的問題...java進程被凍結(?)在linux上

我寫了一個非常簡單的方法,寫一些文本到一個文件。
當然它運作良好,我的機器(XP,4CPU,jdk1.5.0_17 [SUN])
somtimes凍結運行服務器
(Linux的Accounting240 2.4.20-8smp上,4CPU, jdk1.5.0_22 [SUN])。

kill -3不起作用。
ctrl + \不起作用。

所以,我不能告訴你線程轉儲。

凍結以及.. 當我就在這個方法寫一些了Thread.sleep(XX),問題就順利(?)...
睡眠(XX)破......它再次發生今天與Thread.sleep(XX)...

你知道這個問題嗎? 你有一些解決方案嗎? 謝謝。 :-)

P.S.
linux發行版:Red Hat Linux 3.2.2-5
命令:java -cp。牛逼

import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileOutputStream; 
import java.io.OutputStreamWriter; 
import java.text.SimpleDateFormat; 
import java.util.Date; 

public class T { 
private BufferedWriter writer = null; 

private void log(String log) { 
    try { 
     if (writer == null) { 
      File logFile = new File("test.log"); 
      writer = new BufferedWriter(new OutputStreamWriter(
        new FileOutputStream(logFile, true))); 
     } 
     writer.write(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss] ") 
       .format(new Date())); 
     writer.write("[" + log + "]" + "\n"); 
     writer.flush(); 

     /* 
         * this is ad hoc solution ??? 
         */ 
     //Thread.sleep(10); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally {   
    } 

} 

public void test() { 
    long startTime = System.currentTimeMillis(); 

    while (true) { 
     log(String.valueOf(System.currentTimeMillis())); 
     System.out.println(System.currentTimeMillis()); 
     try { 
      //Thread.sleep((int) (Math.random() * 100)); 
     } catch (Exception e) { 
      break; 
     } 

     if (System.currentTimeMillis() - startTime > 1000 * 5) { 
      break; 
     } 
    } 

    if (writer != null) { 
     try { 
      writer.close(); 
     } catch (Exception e) { 
     } 
    } 
    System.out.println("OK"); 
} 

public static void main(String[] args) { 
    new T().test(); 
} 
} 
+2

如果你想做日誌記錄,我強烈建議你使用現有的日誌記錄框架,如果這是一個對你開放的選項。記住log4j或slf4j。 – Buhb 2009-12-09 08:14:29

+0

或java.util.logging。附帶您的JDK。 – Thilo 2009-12-09 08:26:01

+0

在我的雙核Ubuntu AMD64計算機(Sun的「服務器」虛擬機)上運行5次後無法重現。 Java版本 「1.6.0_0」 OpenJDK的運行時環境(IcedTea6 1.6.1)(6b16-1.6.1-3ubuntu1) OpenJDK的64位服務器VM(建14.0-B16,混合模式) – 2009-12-09 08:29:15

回答

2

如果JVM不響應殺-3那麼它是不是你的程序但失敗這是壞的JVM和將需要Sun的一個bug報告

我注意到你正在運行一個2.4.20-8smp內核。這不是目前開源Linux發行版的典型內核,所以我建議你看看http://java.sun.com/j2se/1.5.0/system-configurations.html,看看你是否部署到支持的配置。如果沒有,你應該讓負責任的人知道這一點!

0

第一步是在程序「凍結」時獲取線程轉儲。如果這是在Java 6上,那麼默認情況下可以將JVisualVM或JConsole連接到它,並從那裏獲取所有線程的堆棧跟蹤。因爲它是Java 5,所以你應該能夠使用jstack命令來獲得線程轉儲(或者你可以通過命令行選項來啓用JMX來附加上述工具,但我認爲在這種情況下它不值得) 。在所有情況下,從啓動應用程序的控制檯按Ctrl-Break也可能會產生線程轉儲,具體取決於環境。

這樣做幾秒鐘,然後比較線程轉儲。如果它們總是相同的,那麼它看起來像是你的應用程序被鎖定了;並且轉儲的最上面一行將顯示線程正在阻塞的位置(當您查看該代碼行時,它將提供非常好的線索,它們被阻止的資源)。

在另一方面,如果線程轉儲不時改變,程序不嚴格的僵持狀態,但看起來像它的無限循環中運行 - 也許是你的循環條件之一是不正確聲明所以線程永遠不會退出或這種東西。再次看一下線程轉儲的集合,看看每個線程循環的代碼區域,這會讓您瞭解從未評估退出條件的循環條件。

如果這個問題在這個分析中不是很明顯,那麼回發垃圾箱,因爲它可以幫助人們調試上面的代碼。

+0

是啊~~這次我遇到了這個問題,我有一個尋找和挖掘解決問題的方法。線程轉儲,JConsole就像你說的。 這些是我嘗試的方法。首先,線程轉儲的情況下,Ctrl + \\(Linux)不起作用。並殺死-3 PID不起作用。但我可以通過這些方式看到其他java進程的線程轉儲。這有點奇怪。 其次,JConsole成功連接到凍結的java進程,但監視器數據未顯示在Jconsole UI中。但是我可以看到另一個java進程的彩色圖形監視器數據。啊~~~~現在,我不想試圖解決這個問題。 – uuidcode 2009-12-09 09:38:07

+0

非常感謝Andrzej Doyle .. – uuidcode 2009-12-09 10:01:45

0

我認爲這是一種競爭條件。 while(true)將強制Linux上的虛擬機連續寫入和刷新,並且Linux內核虛擬機將嘗試攔截這些調用並緩衝寫入。這將使進程在等待系統調用完成時進行spinloop;同時,它將被調度程序拾取並分配給另一個CPU(我可能在這裏錯了,tho)。新的CPU將嘗試獲取資源的鎖定,並且所有操作都將導致死鎖。

這可能是未來其他問題的標誌。我建議:

  • 首先,爲了清晰起見:移動log()方法之外的文件創建。這就是構造函數的用途。

  • 其次,你爲什麼要寫這樣的文件?你確定你的程序邏輯首先是有意義的嗎?您是否寧願將日誌消息寫入容器(例如ArrayList),並且每隔XX秒將其轉儲到單獨的線程中的磁盤?現在,您正在限制您的磁盤速度的日誌記錄能力:您可能想要避免的事情。