JVM在退出时挂起

Iva*_*hov 7 java jvm pkcs#11 java-8 windows-8

我正在开发一个小应用程序,应该使用数字签名和退出来签署文档.签名可以在PKCS#12存档(.pfx文件)中或在智能卡设备上.

使用pfx文件很简单,工作正常.

但是,有时使用智能卡设备,该过程会挂起在Windows 8 PC上.

文档已正确签名,但该过程不会终止.它只是挂起.

我正在使用Sun的PKCS#11提供商 - sun.security.pkcs11.SunPKCS11

基本上我这样做:

SunPKCS11 provider = new SunPKCS11(configuration);
Security.addProvider(provider);

..... some work .....

provider.logout()
Security.removeProvider(provider);
Run Code Online (Sandbox Code Playgroud)

现在......即使我System.exit(0)main方法结束时调用或抛出异常,我也可以在输出中看到堆栈跟踪,但进程不会终止.

我添加了一个关闭钩子,看它是否被执行,它是,即JVM正试图停止.

悬挂很少发生,仅在Windows 8 PC上发生.尝试使用不同的智能卡,它只发生在使用的卡上cmp11.dll(dll由智能卡供应商提供).

但是,使用相同的dll与智能卡进行通信在Windows 7,XP或某些Windows 8 PC上运行良好

在x86或x64 Windows 8上使用Java 8,Update 45运行它

试图获取一个线程转储来查看挂起的内容:

public static void main(String[] args) {
  // do my job, register provider, sign documents, remove provider ...

  for(int i = 0; i < 20; ++i) {
    System.err.println("Sleep... " + i);
    Thread.sleep(2 * 1000);
  }
  System.err.println("Exiting...");
}
Run Code Online (Sandbox Code Playgroud)

如果我jstack -l 3232 > dump.log 2>&1Sleep... x打印时执行,一切看起来都还可以.

但是,如果我jstack -F -l 3232 > dump2.log 2>&1Exiting...打印时执行并且应用程序挂起(使用-F因为进程挂起),我得到以下内容:

Attaching to process ID 3232, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.45-b02
Deadlock Detection:

No deadlocks found.

Thread Exception in thread "main"         
java.lang.reflect.InvocationTargetException
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at   sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:497)
      at sun.tools.jstack.JStack.runJStackTool(JStack.java:140)
      at sun.tools.jstack.JStack.main(JStack.java:106)
Caused by: sun.jvm.hotspot.debugger.DebuggerException: Windbg Error: GetThreadIdBySystemId failed!
      at sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal.getThreadIdFromSysId0(Native Method)
      at sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal.getThreadIdFromSysId(WindbgDebuggerLocal.java:284)
      at sun.jvm.hotspot.debugger.windbg.amd64.WindbgAMD64Thread.getThreadID(WindbgAMD64Thread.java:88)
      at sun.jvm.hotspot.debugger.windbg.amd64.WindbgAMD64Thread.toString(WindbgAMD64Thread.java:81)
      at java.lang.String.valueOf(String.java:2982)
      at java.io.PrintStream.print(PrintStream.java:683)
      at sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess.printThreadIDOn(Win32AMD64JavaThreadPDAccess.java:114)
      at sun.jvm.hotspot.runtime.JavaThread.printThreadIDOn(JavaThread.java:265)
      at sun.jvm.hotspot.tools.StackTrace.run(StackTrace.java:79)
      at sun.jvm.hotspot.tools.StackTrace.run(StackTrace.java:45)
      at sun.jvm.hotspot.tools.JStack.run(JStack.java:66)
      at sun.jvm.hotspot.tools.Tool.startInternal(Tool.java:260)
      at sun.jvm.hotspot.tools.Tool.start(Tool.java:223)
      at sun.jvm.hotspot.tools.Tool.execute(Tool.java:118)
      at sun.jvm.hotspot.tools.JStack.main(JStack.java:92)
      ... 6 more
Run Code Online (Sandbox Code Playgroud)

我可以在任务管理器中看到PID 3232的过程!

知道为什么它没有终止或为什么jstack失败?

编辑


好吧,试图在一个单独的进程中提取签名,执行它Runtime.exec然后用它杀死它Process.destroy...似乎没有帮助.子进程仍然留在任务管理器中.

Aaaaand ......现在我别无选择,只能让它自杀;(

try {
  String name = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
  Runtime.getRuntime().exec("taskkill.exe /F /PID " + name.split("@")[0]);
}
catch(Throwable t) {
  Runtime.getRuntime().exec("taskkill.exe /F /IM java.exe"); 
}
Run Code Online (Sandbox Code Playgroud)

编辑2


也试过Runtime.halt.仍然没有终止这个过程......

我很感激任何想法!

Fir*_*fly 1

这不会解决根本原因,但此方法可用于强制 JVM 终止:

http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#halt(int)

正如 Javadoc 所说,请极其谨慎地使用;-)