2016-03-27 65 views
3

在使用system.loadLibrary()函數加載後,刪除庫文件是否正確?這裏是場景...加載到JVM中後刪除臨時文件

我們使用JNI來使用用C語言編寫的DomainSocket實用程序從Java應用程序調用。我們將.SO文件打包到同一個jar文件中,並使用實用程序在文件系統上創建臨時文件,並使用loadLibrary函數加載.SO文件。我們使用File.createTempFile()來創建一個唯一的臨時文件。我們正在使用deteleOnExit()來刪除JVM關閉時的臨時文件。

在JVM上的獨立應用程序中,此工作正常。但是我們在部署到像Tomcat這樣的Web容器時遇到了問題,因爲我們可以在同一個JVM上運行多個應用程序。首先爲每個部署的應用程序創建一個臨時文件。真正的問題是,當App停止並啓動或重新部署時,臨時文件不會被刪除,而是會創建一個新文件。當JVM關閉時(Tomcat重新啓動),所有臨時文件都將被刪除。

我們試驗了一個解決方案,在loadLibrary()之後刪除臨時文件。這似乎工作正常。在重新啓動時創建一個新的臨時文件,並在加載後立即刪除。

想檢查是否有人有一些指標/建議?

我們不希望使用common/lib機制僅爲每個容器加載.SO文件一次,因爲我們希望使這些.SO文件成爲應用程序的一部分。

回答

0

在使用system.loadLibrary()函數加載它之後立即刪除庫文件是否正常...?

沒有。操作系統可以隨時「卸載」庫,並且可能不得不從磁盤重新加載二進制文件。如果你刪除了這個文件(並且它實際上並沒有被這個進程打開),那麼你會得到一些非常奇怪的行爲。可能是像「BUS ERROR」或者其他幾乎不可解釋的情況。

即使庫沒有從內存中刪除並從磁盤重新加載,各種操作系統都會有「延遲加載」標誌和其他可以讓您進入競爭條件的情況,您可能會刪除on-在所有代碼實際上從它加載之前的磁盤庫工件。

我們正在使用File.createTempFile()來創建唯一的臨時文件。我們使用deleteOnExit()來刪除JVM關閉時的臨時文件。

這似乎是一個合理的方法,除了你遇到的問題。爲什麼不在可預見的地方使用可預測的文件名(例如/tmp/libgoodstuff.so),而不是使用File.createTempFile?如果你這樣做,那麼你只需要創建(並安排刪除)單個文件(每個要加載的庫)。

[我]想檢查是否有人有一些指針/建議?

.so文件放在應用程序中將很難管理,除非您非常瞭解您的目標環境。例如,您需要確保您的目標架構和操作系統正確等。

底線是作爲可分發應用程序的一部分的本地庫是一個與Java的脖子痛,應該避免,除非沒有其他選項。

+0

你說什麼操作系統可以隨時卸載庫? – apangin

+0

@apangin我沒有想到特定的操作系統。但是沒有POXIX等要求代碼保持加載狀態,因此基於磁盤的工件可以自由消失。我希望「未定義的行爲」是加載的結果,然後從磁盤上刪除共享庫。 –

+0

嗯,我不知道在刪除共享庫時會導致應用程序崩潰的操作系統(至少在Oracle JDK支持之中)。通常,操作系統會拒絕刪除(Windows)或者只是取消鏈接文件名(Linux),將文件數據保存在磁盤上。刪除文件不會影響已打開的文件的內存映射。 – apangin

0

是的,這種方法可能有效,但有一定的限制。

當調用System.loadLibrary時,相應的.so文件被映射到進程地址空間。當您刪除文件時,將立即刪除相應的dentry,但不會刪除inode。也就是說,文件名是未鏈接的,但文件數據一直保留,直到最後一個文件引用被釋放。

這是軟件包管理器安裝更新的方式。即使運行進程使用它們,它們也可能會刪除可執行文件和共享庫。 OS將確保正在運行的程序繼續使用舊版本的庫,而新程序將加載新版本。

但是,這種方法不便攜。它適用於Linux,但不適用於其他操作系統,不適用於所有文件系統(例如,考慮Windows或FAT)。因此,除非您知道所使用的特定操作系統平臺,否則我不會推薦這麼做。

+0

我們在Web容器中僅使用一個.SO文件來解決問題。由一個webapp加載的.SO文件由於classloader而無法由另一個webapp加載。 Tomact爲每個webapp分配一個獨特的類加載器,並且* same * .SO的多個加載將不起作用... – user2089210

+0

@ user2089210對,我錯過了那部分。因此,如果您不需要該應用程序跨平臺移植,那麼一旦加載它們即可刪除這些庫。那麼,擁有一個JNI庫會使該應用程序無法移植。 – apangin