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
ReflectionAllocator is broken on JDK 16 #1674
Comments
Another idea might be to consider deprecating ReflectionAllocator. |
Deprecating |
Sorry @stephengold, I thought I have already deleted that comment. I guess it's too late to delete it now but I will adjust it to sense a bit nice;) You are right deprecating is another topic that should be discussed on the forum. Regards |
Here's the diagnostic message I got when I ran
|
Using OpenJDK 14.0.2, I get additional diagnostic messages:
After adding the "--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED" JVM argument, the test still crashes similarly with OpenJDK 14.0.2 and even with OpenJDK 11.0.11 . So I don't think this crash has much to do with JDK 16. |
@Ali-RS: I need some help reproducing the "Buffer cannot be destroyed" crash. So far, I haven't even managed to create a buffer with anything other than OpenJDK 8. |
This looks very familiar. This error is typical of binary incompatibility between native libraries and newer builds of the JRE. Last time this came up, I think the only solution was to use lwjgl3, which was built against the newer runtimes. There may be more details on the hub. |
@stephengold can you try with AdoptOpenJDK? AFAIK LWJGL2 is not compatible with OpenJDK 12+ (also with some versions of OpenJDK 11, IIRC 11.0.6+) Otherwise, I think you should use LWJGL3 as mentioned by Sailsman63. I'm sorry I did not clarify this in advance. |
Chiming in on @stephengold's request. I'm running on an Oracle build of JDK 16 with LWJGL 3 with no issues. |
@stephengold were you able to reproduce the "Buffer cannot be destroyed" crash? |
I never got that far. |
A note for anyone who wants to try this with LWJGL3: LWJGL3 will statically register its own buffer allocator at LwjglContext: jmonkeyengine/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java Lines 93 to 104 in ceb3564
which will be statically initialized at this line into the final field
So you must make sure to register
|
The ReflectionAllocator was an hack to begin with. Does anyone know if it is used outside of the lwjgl2 renderer?
It seems we should find a different way to set the allocator, maybe the renderers should have the buffer allocator under the same class name and namespace so that when the modules are switched it gets replaced without setting it "manually". |
Yes, For Android, a workaround may be to write a JNI-based allocator that uses c++ to crete and destroy DirectByteBuffer. Something like:
another workaround is to use |
We already have the jme3-android-native module, the JNI allocator can be added there. |
To elaborate on this: The first part of my proposal is to have a NativeAllocator that is implemented by every rendered module internally (eg. lwjgl3 will use its allocator, lwjgl2 will use ReflectionAllocator, android will use the jni allocator) with the same class on the same path: com.jme3.util.NativeAllocator . The next step of the solution is to have BufferAllocatorFactory load the allocator that is specified with the property PROPERTY_BUFFER_ALLOCATOR_IMPLEMENTATION like it does now, but with the default always being com.jme3.util.NativeAllocator, and if the specified class doesn't exist make it fallback to PrimitiveAllocator. That should solve or provide a path to solve every possible issue. What do you think? |
Is |
A class that implements BufferAllocator |
Ok, that sounds good to me. |
The idea of a NativeAllocator seems good to me too, i will try to implement it for android. |
Thank you @Scrappers-glitch |
Btw, android internals use the same maneuver under The native binding for allocating mem on gpu : The native lib : Sources at Android cs : |
@Ali-RS This may be why you have experienced this bug on JDK-16 and it's absent on other jdks, |
And in particular, there has been a serious push to remove the However, if that were the cause you should be getting |
Or guarded against reflective calls...i don't know why generally, but on android they made java reflection and invocation api a black list. |
Mostly security. Reflection allows access to APIs that may not be safe for general code to use. Even desktop Java is moving to block reflection to a lot of internal packages. But in that case, you should be getting |
I am done with Android Native buffer allocator, but there is something which is inconsistent, on |
Based on riccardobl suggestion:
I suppose we should put it under the |
Once all architectures are built into |
No problem, take your time and ask it on the forum if you need help. |
Okay, unless there is an objection to my proposal (using CMake + gradle), i am going to start soon and i will open a forum thread to keep the community updated with the latest status about |
Before we build our own native dependency to only call One that is available to jwgl3 is jemalloc: https://javadoc.lwjgl.org/org/lwjgl/system/jemalloc/JEmalloc.html Especially the hint to project panama is interesting, if you have a completely new API also supporting try-with-resources.
And most importantly:
-> So the Java Devs consider JNI (us wrapping malloc) worse than unsafe/byte buffer. Keep in mind a java allocator could allocate bigger byte buffers manually and then only giving out chunks. But then, we only use it for Megabyte Sized Textures (well and small vert/index buffers.... Could probably also pool them) So in general, I can't recommend anything right now, but if our buffers are mainly to communicate with openGL, memory mapping with a new API may be interesting. And a specialized allocator may make a difference, too. With malloc I don't know how thread safety looks like etc and you'd still need to get the native address of the byte buffer and try to wrap it etc. Furthermore, I wouldn't recommend cmake for something so simple, since you need visual studio and the cmake workload on windows, on mac os probably XCode (my mac can't even use any recent XCode anymore because it's "old") etc. |
@MeFisto94 Yes, you are right, we shouldn't create a new API for just malloc(), if using jemalloc will be enough then let me know. About multi-threading and thread safety in jni:
I think i didn't respect this point while building android native buffer so far, so thank you for pointing this out, i totally forgot. |
I am okay using lwjgl3 jemalloc lib. Can we use it without depending on lwjgl3-core? |
I think it cannot, this is a script generated by lwjgl.org/customize. import org.gradle.internal.os.OperatingSystem
project.ext.lwjglVersion = "3.3.1"
switch (OperatingSystem.current()) {
case OperatingSystem.LINUX:
def osArch = System.getProperty("os.arch")
project.ext.lwjglNatives = osArch.startsWith("arm") || osArch.startsWith("aarch64")
? "natives-linux-${osArch.contains("64") || osArch.startsWith("armv8") ? "arm64" : "arm32"}"
: "natives-linux"
break
case OperatingSystem.MAC_OS:
project.ext.lwjglNatives = System.getProperty("os.arch").startsWith("aarch64") ? "natives-macos-arm64" : "natives-macos"
break
case OperatingSystem.WINDOWS:
def osArch = System.getProperty("os.arch")
project.ext.lwjglNatives = osArch.contains("64")
? "natives-windows${osArch.startsWith("aarch64") ? "-arm64" : ""}"
: "natives-windows-x86"
break
}
repositories {
mavenCentral()
}
dependencies {
implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
implementation "org.lwjgl:lwjgl"
implementation "org.lwjgl:lwjgl-jemalloc"
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
runtimeOnly "org.lwjgl:lwjgl-jemalloc::$lwjglNatives"
} |
Now, i am totally sure it cannot be used without lwjgl-core, it utilizes the lwjgl-core system package: |
Just my two cents! If you think it is possible to rip only the required java code + natives from lwjgl3 then go that way but if you think creating our own thin API around malloc/calloc would be easier, then do that way, or if you think it would be easy to use You can use whatever build tool you are familiar with it does not matter. What matters is that we want a
The jar should be hosted on maven central (either under Simillar to what @stephengold did with https://github.com/stephengold/j-ogg-all/ and https://github.com/stephengold/stack-alloc Edit: You can also take a look at how LibGdx does this in there buffer allocator: |
I realized that the code we implemented on android is really doing this indeed :-), but this option renders the same solution as our own API, we will have to recompile sources. It's not possible to separate jemalloc from lwjgl3-core and lwjgl3-natives. |
In theory, an allocator is the backbone of an application, so don't over-rush this please. Tuning the allocator is also yet another topic. |
AFAIK, malloc() allocates new memory on the native heap which is visible to the jvm, use |
Visible but not managed by. I don't know if this is really a concern or not. One of the big problems with Java6 was having to specify a huge direct heap because GC would free direct memory but did not consider it when deciding to run GC. There is a concern that if we move to memory that Java does not manage that maybe we return to those awful days. That would be unfortunate. I admit I have not looked into what's going on here, though. Not really something to take lightly in the alpha phase of a piece of software maybe. |
Any modern C (or C++) compiler should provide a runtime library with thread-safe malloc()/free(). |
Okay, i think we are left with an additional option which is creating a new minimalistic allocation api ( @stephengold Let me know your opinion about this option if this is feasible, and also if this will cause any conflict for people who still use other bullet physics libraries, if we are good with this option, assign me to this and i will work on a PR to the libbulletjme to add the BufferUtils and another PR to the engine to utilize a new |
I'm willing to create a new library for buffer allocation and deallocation, using a weak-reference tracking mechanism similar to what Libbulletjme uses for physics objects. However, I don't have a clear sense of how long it would take, and I'm unclear how much time remains before the JME 3.6 code freeze. |
It can be a separate project independent of JME releases. |
Okay, i have a raw Algorithm library arithmos, it's a standalone project with no dependencies, i will just refactor it to use any of gradle-jni-templates to get myself familiar with this until we reach a solution, i guess what will take most of the time (if not all) is building to windows and Mac systems, otherwise coding will not be a very hard task. |
Note that the |
But first, I'm unclear why we even need |
May be using low-memory desktop devices like raspberries or Risc-V MCU ? It may give us some memory performance. |
Related discussion at the Discourse Forum/Hub: https://hub.jmonkeyengine.org/t/jme-alloc-project/46356 |
I was wrong ! This project aims to provide a backward compatible direct memory allocation api for desktop on lwjgl-2. Currently, I managed to build x86-64 binaries for Linux, Mac and windows. I cannot build x86 binaries; because github-runners don't provide x86 systems, so there are 2 options, either to use another CI to build the other variants or create workarounds by downloading their toolchains in their respective systems (so for example downloading GCC for x86 Intel or looking around GCC options to provide a backward compatibility for the output binary). |
SEVERE: Buffer cannot be destroyed: java.nio.DirectFloatBufferU
Even by adding this JVM arg (which used to solve that on jdk 11+)
"--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED"
you can test it with
jmonkeyengine/jme3-examples/src/main/java/jme3test/app/TestReleaseDirectMemory.java
Line 43 in d76d4dc
Forum post:
https://hub.jmonkeyengine.org/t/jme-on-jdk-16/44411/6?u=ali_rs
The text was updated successfully, but these errors were encountered: