Comparison between jME2 and jME3

Are you talking about just getting rid of the NativeObject or the direct buffer that it contains? Note: If you delete a direct buffer that is still in use then you get JVM crashes and/or random garbage. So this needs to be managed extra carefully on the part of the caller.

Actually i would gove it a option to allow do both (do not force deletion of the direct buffer, as not all jvm has that Cleaner class, also problems as you mentiond) but all use nativeobject.

After all tihs is not for the common usecase, but for stuff where it really matters, (like large terrain maps ect)

<cite>@Empire Phoenix said:</cite> Actually i would gove it a option to allow do both (do not force deletion of the direct buffer, as not all jvm has that Cleaner class, also problems as you mentiond) but all use nativeobject.

After all tihs is not for the common usecase, but for stuff where it really matters, (like large terrain maps ect)


Currently in my copy it is a separate method (NativeObject.deleteNativeBuffers). If you want to delete both, you can call deleteObject() and deleteNativeBuffers() together.

Is there a reason to distinguish between deleting a memory buffer and a native object?
I mean, both have the same requirements: Must not be deleted more than once.
Okay, the graphics driver will probably crash less often, but it could still get into trouble if asked to do a double free.

Either way, explicitly freeing memory is always risky. I’d put a big fat warning on any routines that allow doing that.

<cite>@toolforger said:</cite> Is there a reason to distinguish between deleting a memory buffer and a native object? I mean, both have the same requirements: Must not be deleted more than once. Okay, the graphics driver will probably crash less often, but it could still get into trouble if asked to do a double free.

Either way, explicitly freeing memory is always risky. I’d put a big fat warning on any routines that allow doing that.

Just to be clear, you can delete the buffer as often as you want but the pointer to it is not cleared. So if something accesses it (like an Image, VertexBuffer, etc.) then it’s either garbage or you crash the JVM.

My concern would be the users who do not understand what this method does but see it pop up in their IDE when they start typing. Using it without full understanding is super-duper bad.

<cite>@toolforger said:</cite> Is there a reason to distinguish between deleting a memory buffer and a native object?
From the engine point of view, yes, because the lifetime of GL objects and native buffers is completely different. From user point of view, probably not, as they are just indicating "I don't want to use this object anymore".
<cite>@pspeed said:</cite> Just to be clear, you can delete the buffer as often as you want but the pointer to it is not cleared. So if something accesses it (like an Image, VertexBuffer, etc.) then it's either garbage or you crash the JVM.

Yes, that’s the dangling pointer problem.

But a double free should also be avoided. Imagine the sequence of: block is freed, block happens to be allocated again by some other code, double free. Now the sandwiched allocation has a dangling pointer.
I think that situation is the reason why Valgrind still reports double frees.
(Double frees used to be a richer source of crashes decades ago when a double free would corrupt heap management data structures. Today’s memory managers are more robust, but that doesn’t prevent all crashes.)

<cite>@pspeed said:</cite> Just to be clear, you can delete the buffer as often as you want but the pointer to it is not cleared.

NativeObjectManager can clear out the pointer in the NativeObject on the first free.
Of course, Java code must not copy the pointer to some other location, but NativeObject shields it from that (I hope, if it doesn’t, put something into the class Javadoc).

<cite>@pspeed said:</cite> My concern would be the users who do not understand what this method does but see it pop up in their IDE when they start typing. Using it without full understanding is super-duper bad.

Hm… do the NativeObject routines crash if the pointer is nulled out?
If they just fail (throw a NPE or whatever) before dropping to C code, that would just be a normal exception trace. Bad, but not super-duper bad.

If it’s super-duper bad, add a fat warning to the javadoc. At least in Eclipse, code completion gives access to the Javadoc.
We can’t protect people from ignoring the docs (yeah I know they still do :frowning: - but hopefully those who do explicit memory management are pro enough to actually read docs)

<cite>@Momoko_Fan said:</cite> From the engine point of view, yes, because the lifetime of GL objects and native buffers is completely different.

Unless a NativeObject is managing both a GL object and a native buffer, that shouldn’t matter from the perspective of NativeObjectManager.
(I haven’t seen both in the same NativeObject, but I may not have looked hard enough.)

We should be clear what we are talking about. I’m talking about destroying buffers since that’s what actually takes up memory and what actually matters at the end of the day.

If you use the back door to delete a buffer and then try to continue using at, at best you will be messing with garbage, at worst you crash your JVM with a heap dump. Java doesn’t provide any way to officially delete a buffer.

If we aren’t talking about deleting buffers then what’s the benefit of destroying a native object?

Well the native object uses memory as well, eg a 512mb texture is either on the vram or swapped to main ram, but it is somewhere. If you know its not usefull, you can clear it to prevent lags or oom erros in the opengl layer. (Best example regenerating a lightmap, the old one is completely useless instantly, no need to wait for the gc.

<cite>@Empire Phoenix said:</cite> Well the native object uses memory as well, eg a 512mb texture is either on the vram or swapped to main ram, but it is somewhere. If you know its not usefull, you can clear it to prevent lags or oom erros in the opengl layer. (Best example regenerating a lightmap, the old one is completely useless instantly, no need to wait for the gc.

This goes against my understanding a bit. 512 mb texture is a 512 mb native buffer (direct memory)… that occasionally will get mapped to VRAM if necessary. So, yes, it might be hanging around in VRAM but that will be much more tightly managed by OpenGL… if that VRAM is needed by something else now then it won’t be there anymore. The native buffer, however, won’t go away until you tell it to or GC collects it.

Yes, the vram is not that much of a problem, its more of a nice to have if we do some kind of api for it

<cite>@Empire Phoenix said:</cite> Yes, the vram is not that much of a problem, its more of a nice to have if we do some kind of api for it

From the OpenGL side the VRAM is invisible, its not even part of the spec. You cannot control what data resides in it, the driver does.

So, to draw conclusions:
-benefits of destroying a NativeObject sans buffer = barely none
-benefits of destroying a direct buffer = memory is available again

…but manual memory management is not a good idea for the uninitiated.

@pspeed: There’s also a driver side copy of the texture on the CPU, so deleting it from GL is just as important as deleting from Java’s direct memory heap.

In any case, here’s what I am proposing:
NativeObject.dispose():

  1. Reclaims both native buffers and GL memory corresponding to the object.
  2. Can be called from any thread, since it just en-queues the object for deletion on the next frame by the NativeObjectManager.
  3. Marks that object as disposed. If assertions are turned ON => an AssertionError is always thrown when trying to use a disposed object. If assertions are turned OFF => it might throw an exception, such as NPE, or Buffer underflow exception, or nothing happens at all. The only guarantee is that there won’t be a native crash.

What do you think?

<cite>@Momoko_Fan said:</cite> @pspeed: There's also a driver side copy of the texture on the CPU, so deleting it from GL is just as important as deleting from Java's direct memory heap.

Why give it direct buffers if it isn’t using them?

So are there potentially 4 copies in memory of each texture?

(Java, direct buffers, driver, GPU) ?

<cite>@zarch said:</cite> So are there potentially 4 copies in memory of each texture?

(Java, direct buffers, driver, GPU) ?


Only 3 copies (potentially). 1 copy in native buffers, 1 copy in the driver, and 1 copy in VRAM but only if the texture was used recently for rendering.

<cite>@pspeed said:</cite> Why give it direct buffers if it isn't using them?
I don't think I understand the question.. Give direct buffers to who?
<cite>@Momoko_Fan said:</cite> Only 3 copies (potentially). 1 copy in native buffers, 1 copy in the driver, and 1 copy in VRAM but only if the texture was used recently for rendering.

I don’t think I understand the question… Give direct buffers to who?

We give direct buffers to OpenGL. If it’s just going to copy them again then why do we have to give it direct buffers. Seems to defeat the purpose of using direct memory.

Also, this driver memory must be hidden because it doesn’t show up in task manager. It’s magic hidden memory.

<cite>@pspeed said:</cite> We give direct buffers to OpenGL. If it's just going to copy them again then why do we have to give it direct buffers. Seems to defeat the purpose of using direct memory.
I guess so, this is a requirement from LWJGL and not from us. Maybe there's some performance overhead with "pinning" a byte array as opposed to just giving it a pointer to native memory.
<cite>@pspeed said:</cite> Also, this driver memory must be hidden because it doesn't show up in task manager. It's magic hidden memory.
Maybe drivers keep the data in VRAM until there's no more space there, and only then take it back into system memory (after all texture / buffer IDs die when the GL context dies). I can only guess as to the way the drivers work, but I do know that at the worst case you could end up with 3 copies of the data.