Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jpy destroy_jvm freezes #103

Open
makovez opened this issue May 28, 2023 · 7 comments
Open

jpy destroy_jvm freezes #103

makovez opened this issue May 28, 2023 · 7 comments
Assignees

Comments

@makovez
Copy link

makovez commented May 28, 2023

Hi,

I'm using jpy version inside snappy package, and when i call jpy.destroy_jvm() it hangs and freezes without returning nothing.

Can you confirm if you guys have same problem?

@makovez makovez changed the title jpy desotry_jvm freezes jpy destroy_jvm freezes May 28, 2023
@devinrsmith devinrsmith self-assigned this Jun 20, 2023
@devinrsmith
Copy link
Member

Hi @makovez can you give some more details about your environment? jpy version, cpython version, java version, OS, etc.

destroy_jvm() is working for me with jpy==0.13.0, cpython 3.11.3, Linux x86_64, OpenJDK 11.0.19 (as well as 17.0.7).

$ python3 -m venv /tmp/jpy

$ /tmp/jpy/bin/pip install jpy
Collecting jpy
  Using cached jpy-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (344 kB)
Installing collected packages: jpy
Successfully installed jpy-0.13.0

$ JAVA_HOME=/usr/lib/jvm/java-11 /tmp/jpy/bin/python
Python 3.11.3 (main, May 24 2023, 00:00:00) [GCC 13.1.1 20230511 (Red Hat 13.1.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import jpyutil
>>> jpyutil.preload_jvm_dll()
<CDLL '/usr/lib/jvm/java-11/lib/server/libjvm.so', handle 55c4bb9f9220 at 0x7f752dd50610>
>>> import jpy
>>> jpy.has_jvm()
False
>>> jpy.create_jvm([])
>>> jpy.has_jvm()
True
>>> jpy.get_type('java.lang.System').out.println('Hello from Java')
Hello from Java
>>> jpy.destroy_jvm()
>>> jpy.has_jvm()
False

@makovez
Copy link
Author

makovez commented Jun 20, 2023

I'm using the jpy package which is inside snappy of snap last version 9.0 which is jpy-0.9.0

And i'm using jdk 1.8

All from windows or Linux is same.

@devinrsmith
Copy link
Member

Are you able to take a stack trace during the freeze?

https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#DestroyJavaVM

If the current thread is attached, the VM waits until the current thread is the only non-daemon user-level Java thread. If the current thread is not attached, the VM attaches the current thread and then waits until the current thread is the only non-daemon user-level thread.

I suspect you may have non-daemon threads that aren't shutting down?

@makovez
Copy link
Author

makovez commented Jun 20, 2023

How can i take a stack trace if frozen?

I'm not using any threads. I'm just running it from python console

image

This is the init.py script snappy that runs when i do from snappy import jpy https://github.com/senbox-org/snap-engine/blob/aacdf9524ee0e541746001c5919ab2b71f408e80/snap-python/src/main/resources/snappy/__init__.py

@devinrsmith
Copy link
Member

I'm not sure on Windows, but on Linux you can use kill -3 <pid> or jstack <pid>. Looks like jstack.exe is available for Windows: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jstack.html, https://access.redhat.com/solutions/19170

@makovez
Copy link
Author

makovez commented Jun 21, 2023

I runned it on the python process.

C:\Users\s>jstack 14552
2023-06-21 09:19:04
Full thread dump OpenJDK 64-Bit Server VM (25.242-b20 mixed mode):

"pool-1-thread-1" #13 prio=5 os_prio=0 tid=0x000002147ca93000 nid=0x4470 waiting on condition [0x000000f9b2e6f000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000004c05f4aa0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2083)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

"WeakCollectionCleaner" #12 daemon prio=8 os_prio=1 tid=0x000002147c5a3800 nid=0x5620 in Object.wait() [0x000000f9b2c7e000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000004c05fca70> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
        - locked <0x00000004c05fca70> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
        at org.geotools.util.WeakCollectionCleaner.run(WeakCollectionCleaner.java:66)

"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x000002147a40e800 nid=0x44f0 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #9 daemon prio=9 os_prio=2 tid=0x000002147a3f8800 nid=0x5aa8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x000002147a3c1000 nid=0x681c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x000002147a3a3000 nid=0x559c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000002147a3a0000 nid=0x6194 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000002147a397800 nid=0x5524 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000002147a396800 nid=0x55d0 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000002147a377000 nid=0x5e40 in Object.wait() [0x000000f9b1b0f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000004c05fd378> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
        - locked <0x00000004c05fd378> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000002147a370800 nid=0x4e00 in Object.wait() [0x000000f9b191f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000004c05fd530> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x00000004c05fd530> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 prio=5 os_prio=0 tid=0x00000214737ae000 nid=0x46f8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"VM Thread" os_prio=2 tid=0x0000021478695000 nid=0x6198 runnable

"ParGC Thread#0" os_prio=0 tid=0x00000214736cc000 nid=0x6b30 runnable

"ParGC Thread#1" os_prio=0 tid=0x00000214736ce000 nid=0x25f4 runnable

"ParGC Thread#2" os_prio=0 tid=0x00000214736cf800 nid=0x6004 runnable

"ParGC Thread#3" os_prio=0 tid=0x00000214736d1000 nid=0x3c8 runnable

"ParGC Thread#4" os_prio=0 tid=0x00000214736d3800 nid=0x6f0c runnable

"ParGC Thread#5" os_prio=0 tid=0x00000214736d4800 nid=0x486c runnable

"ParGC Thread#6" os_prio=0 tid=0x00000214736d8800 nid=0x2a64 runnable

"ParGC Thread#7" os_prio=0 tid=0x00000214736da000 nid=0x6e14 runnable

"VM Periodic Task Thread" os_prio=2 tid=0x000002147a410000 nid=0x5cf0 waiting on condition

JNI global references: 937

@devinrsmith
Copy link
Member

I'm able to reproduce this behavior by starting a non-daemon thread pool:

>>> import jpy
>>> JExecutors = jpy.get_type('java.util.concurrent.Executors')
>>> JThreadPoolExecutor = jpy.get_type('java.util.concurrent.ThreadPoolExecutor')
>>> my_pool = jpy.cast(JExecutors.newFixedThreadPool(1), JThreadPoolExecutor)
>>> my_pool.prestartCoreThread()
True
>>> jpy.destroy_jvm()

If you are able to stop the pool first, the destroy_jvm() should complete successfully. You might want to check in with https://github.com/senbox-org/snap-engine to see if this is something they allow you to do?

There's also a question of "is jpy invoking destroy_jvm() in a manner that lets java know it's shutting down". That deserves some further investigation on our end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants