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

Fatal Error in native method: bad global or local ref passed to JNI #617

Open
MartinHaeusler opened this issue Apr 21, 2024 · 8 comments
Open
Labels
bug Something isn't working

Comments

@MartinHaeusler
Copy link
Contributor

The following happened randomly to me today while test playing my game:

FATAL ERROR in native method: Bad global or local ref passed to JNI
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x9b28bf]  ReportJNIFatalError+0x2f
V  [libjvm.so+0x9bbc6a]
V  [libjvm.so+0x9be5e6]  checked_jni_DeleteGlobalRef+0x96
C  [godot.linuxbsd.editor.x86_64+0xca05da]

Unfortunately that's all I have, there were no more logs available from this particular crash. I don't know which JNI method it was, nor which reference was problematic. I thought I should report this anyway, perhaps we can at least improve the logging to include the called method name or other diagnostic information.

@piiertho
Copy link
Member

We will add debug symbols for debug build in a next release.
Which version are you using ? We can still disassemble binary and look where it crashes using adresse

@MartinHaeusler
Copy link
Contributor Author

@piiertho I'm currently on 0.8.1-4.2.0. Hoping for a new version that targets Godot 4.2.2 soon :)

@CedNaru
Copy link
Member

CedNaru commented Apr 21, 2024

It at least tells us it's related to deleting a global ref from the c++ side, and if it rarely and randomly happens, it means it's a race condition.
Most likely, it's the issue I talked about here:
#616

@CedNaru CedNaru added the bug Something isn't working label Apr 21, 2024
@MartinHaeusler
Copy link
Contributor Author

MartinHaeusler commented Apr 23, 2024

Got another one...

FATAL ERROR in native method: Bad global or local ref passed to JNI
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x9b28bf]  ReportJNIFatalError+0x2f
V  [libjvm.so+0x9bbb70]  checked_jni_NewWeakGlobalRef+0x140

This is quite concerning to me because it seems totally non-deterministic and I can't do anything about it. During play testing it's a minor annoyance, but for a release candidate that's really bad.

It could also be that I made some coding error, but at the moment I can't really tell because I have no diagnostic information.

@CedNaru
Copy link
Member

CedNaru commented Apr 23, 2024

It's very unlikely to be your mistake, users code is not supposed to have any influence on how the module handle the JNI ref.
It's random because it's probably a race condition between Godot main thread and the MemoryManager thread we use.
I have a few ideas on the origin of it.

@MartinHaeusler
Copy link
Contributor Author

@CedNaru I saw your proposal in #618 and for what my opinion is worth, the proposal makes sense to me. Maybe it could also be worth a try to see how it's done for the Godot C# module? After all, in the grand scheme of things, the CLR and the JVM are similar beasts and the CLR has its own GC as well.

Any attempt at fixing this issue would be highly appreciated, as it ultimately is a showstopper. Individual issues I can work around; random crashes are a different story.

@CedNaru
Copy link
Member

CedNaru commented Apr 24, 2024

I already checked how C# does it and actually, the second point of my proposal is to move away from the way C# is managing its memory (because we are currently doing the same things as them).

The way they handle bindings is not right in my opinion. Like I explain in the proposal, this model make it so that the VM (CLR or JVM) is the one with the last word on the memory. If we were to run an experiment and use C# and Kotlin in the same Godot project, you would end up with a lot of memory leaks because the 2 VM would prevent each other from deleting RefCounted instances (if they are bound to the 2 VM at the same time). We used their code a lot as a reference when starting this project, but we tend to ignore it now that we got more experience with Godot internals. Their module is quite bloated in an inefficient way.

Both are VM but the way they do interop is totally different, there are things you can afford to do in C#, but can't with the JVM because of JNI performances. Our main bottleneck regarding performances is the number of JNI calls, the more of them we can avoid, the better the performances will be.

@CedNaru
Copy link
Member

CedNaru commented May 12, 2024

#626 is an attempt at fixing that issue. Given that it's random and rare, it's hard to figure out what is the exact cause.
I went over all the code that manages the memory between Godot and JVM and found several parts that will rarely but eventually trigger bugs. So no guarantee sadly.
I'll keep this issue open until the next release and you make sure the issue is gone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants