Java 没有在应用关闭时释放所有资源
Java doesn't release all resources on app close
我有两个 javafx 应用程序和更新程序。
App 使用 Firebird 数据库来存储一些脆弱的用户数据。数据库以嵌入式模式运行(我认为这是相关的),因此这意味着同一时间只能有一个到数据库的连接(数据库创建一个锁定文件)。
Updater 更新 App.
整个架构如下所示:
- 用户运行 App-> App 正在检查是否需要更新,如果需要,则它启动更新程序(使用 java ProcessBuilder)并自行关闭(Platform.exit())。
- 更新程序检查应用程序是否已正确终止。
- Updater 运行命令 "App --export-user-data"(也使用 ProcessBuilder)以在开始更新之前导出最重要的内容(必须以这种方式完成 - 我无法将此功能移至 Updater)。
- 应用程序首先冻结 session.beginTransaction() - 没有单一错误或异常
目前观察到的情况:
- 当我启动应用程序并按 [X] 关闭它时,所有
来自 "C:\ProgramData\firebird" 的锁定文件被删除,但是当 App
启动更新程序并自行关闭,然后锁定文件保持不变。我认为这就是 Hibernate 无法开始事务的原因。
- Updater的进程不是App的子进程(我用进程监视器查过了)
- 当我直接启动 Updater 时,它就像一个魅力 - 所以只有当 App 启动 Updater 时问题才会出现。
我不能做的事情:
- 将数据库切换到其他任何数据库 - 它必须是 firebird 嵌入的
- 将导出功能移至更新程序
即使是最奇怪的想法,我也会很感激,因为我花了四天时间试图解决这个问题。
编辑:
火鸟版本:2.1
Jaybird 版本:2.1.6
Updater的启动方式(只做必要的事情)
public void startUpdater(){
ProcessBuilder pb = new ProcessBuilder(updaterPath, argument)
pb.start();
Platform.exit();
}
经过长时间的斗争,我终于找到了解决办法。当 java 创建一个新进程时,子进程会继承其父进程的所有句柄。这就是为什么 firebird 锁定文件没有被删除的原因。我通过在 cpp 中创建小应用程序并在 运行 updater.
时将其用作代理来解决这个问题
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if( argc != 2 )
{
printf("Usage: %s [cmdline]\n", argv[0]);
return 0;
}
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return 0;
}
}
我有两个 javafx 应用程序和更新程序。 App 使用 Firebird 数据库来存储一些脆弱的用户数据。数据库以嵌入式模式运行(我认为这是相关的),因此这意味着同一时间只能有一个到数据库的连接(数据库创建一个锁定文件)。 Updater 更新 App.
整个架构如下所示:
- 用户运行 App-> App 正在检查是否需要更新,如果需要,则它启动更新程序(使用 java ProcessBuilder)并自行关闭(Platform.exit())。
- 更新程序检查应用程序是否已正确终止。
- Updater 运行命令 "App --export-user-data"(也使用 ProcessBuilder)以在开始更新之前导出最重要的内容(必须以这种方式完成 - 我无法将此功能移至 Updater)。
- 应用程序首先冻结 session.beginTransaction() - 没有单一错误或异常
目前观察到的情况:
- 当我启动应用程序并按 [X] 关闭它时,所有 来自 "C:\ProgramData\firebird" 的锁定文件被删除,但是当 App 启动更新程序并自行关闭,然后锁定文件保持不变。我认为这就是 Hibernate 无法开始事务的原因。
- Updater的进程不是App的子进程(我用进程监视器查过了)
- 当我直接启动 Updater 时,它就像一个魅力 - 所以只有当 App 启动 Updater 时问题才会出现。
我不能做的事情:
- 将数据库切换到其他任何数据库 - 它必须是 firebird 嵌入的
- 将导出功能移至更新程序
即使是最奇怪的想法,我也会很感激,因为我花了四天时间试图解决这个问题。
编辑: 火鸟版本:2.1 Jaybird 版本:2.1.6
Updater的启动方式(只做必要的事情)
public void startUpdater(){
ProcessBuilder pb = new ProcessBuilder(updaterPath, argument)
pb.start();
Platform.exit();
}
经过长时间的斗争,我终于找到了解决办法。当 java 创建一个新进程时,子进程会继承其父进程的所有句柄。这就是为什么 firebird 锁定文件没有被删除的原因。我通过在 cpp 中创建小应用程序并在 运行 updater.
时将其用作代理来解决这个问题#include <windows.h>
#include <stdio.h>
#include <tchar.h>
int _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if( argc != 2 )
{
printf("Usage: %s [cmdline]\n", argv[0]);
return 0;
}
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return 0;
}
}