LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: bobjob on July 09, 2017, 05:29:15

Title: [Solved] Errors when using newer version of LWJGL 3
Post by: bobjob on July 09, 2017, 05:29:15
I have been using:
LWJGL 3.1.1 SNAPSHOT build 1

and my code works fine

I then switched to:
LWJGL 3.1.2 build 29

And I am now getting temperamental errors.
My program will work sometimes, but then other times it will either crash
or output something like to many errors to report:


The only changes required in my code where as follows
this:

  ByteBuffer newImage =
    Stdlib.malloc(scaleWidth * scaleHeight * comp.get(0));

to this:

    ByteBuffer newImage =
    LibCStdlib.malloc(scaleWidth * scaleHeight * comp.get(0));


Also another error I have observed is that sometimes only every second mouse click works



I have attached the error log on the last crash
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 09, 2017, 05:49:46
I also get this output:
Quotejava(590,0x7fffcb4d73c0) malloc: *** error for object 0x7fd2f4e445a8: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug

Im guessing its a memory leak, I just don't understand why It wasn't causing errors before
Title: Re: Errors when using newer version of LWJGL 3
Post by: spasi on July 09, 2017, 07:55:07
Sounds like you're allocating with one memory allocator and freeing with another.

The memAlloc*/memFree methods in MemoryUtil use a configurable memory allocator. It can be the system allocator (from the LibCStdlib class), jemalloc (from the JEmalloc class), or a user-specified allocator. This allocator is also used internally by LWJGL in various places. For example, when you call .free() on a struct, it assumes that the struct has been allocated with memAlloc and calls memFree. If MemoryUtil has been configured to use jemalloc and you had allocated the struct using direct calls to LibCStdlib, then the free is going to crash.

Suggestions that may fix the problem:

- Do not use the allocator bindings directly, always use MemoryUtil.
- If you do use an allocator directly, make sure MemoryUtil is configured to use the same allocator.
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 09, 2017, 11:38:40
Thanks for you help spasi. I am trying to track down all the calls to allocate and free memory. It seems as though all of them are using memory utils. The only issue I can think that may be causing this is that I am allocate memory in a seperate thread, and then after the object is loaded I am freeing it in the main thread.

how do I "set a breakpoint in malloc_error_break to debug"?
I would really like to know which free/alloc is causing this error. As its temperamental and doesn't happen all the time which makes it very hard to locate
Title: Re: Errors when using newer version of LWJGL 3
Post by: spasi on July 09, 2017, 12:35:33
That message comes from jemalloc, so it's not really applicable. You can set a Java breakpoint to memFree though, should achieve the same result.

You can also try -Dorg.lwjgl.util.DebugAllocator=true and -Dorg.lwjgl.util.Debug=true. It will report memory leaks on exit (for memAlloc only).
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 09, 2017, 12:38:49
THANK YOU! that helps a lot. getting a lot more useful debug info
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 09, 2017, 14:41:57
Im pretty sure the issue is related to multi-thread. which explains why it only happens sometimes:

This is the code that Im using to load in another thread. If I do this in the main thread, the program works every time.
But when I move it back into the loading thread, it crashes sometimes

ByteBuffer ttf = IOUtil.ioResourceToByteBuffer(name, 160 * 1024);


STBTruetype.stbtt_PackBegin(pc, bitmap, BITMAP_W, BITMAP_H, 0, 1);

for ( int i = 0; i < scale.length; i++ ) {
int z = 0;
for (int s = 0; s < samples; s++) {
if (sf[s + (samples * i)] == 0) {
int p = (i * samples + z) * 128 + 32;
chardata.limit(p + 95);
chardata.position(p);
org.lwjgl.stb.STBTruetype.stbtt_PackSetOversampling(pc, 1, 1);
org.lwjgl.stb.STBTruetype.stbtt_PackFontRange(pc, ttf, 0, scale[i], 32, chardata);
z++;
}
if (sf[s + (samples * i)] == 1) {
int p = (i * samples + z) * 128 + 32;
chardata.limit(p + 95);
chardata.position(p);
org.lwjgl.stb.STBTruetype.stbtt_PackSetOversampling(pc, 2, 2);
org.lwjgl.stb.STBTruetype.stbtt_PackFontRange(pc, ttf, 0, scale[i], 32, chardata);
z++;
}
if (sf[s + (samples * i)] == 2) {
int p = (i * samples + z) * 128 + 32;
chardata.limit(p + 95);
chardata.position(p);
org.lwjgl.stb.STBTruetype.stbtt_PackSetOversampling(pc, 3, 1);
org.lwjgl.stb.STBTruetype.stbtt_PackFontRange(pc, ttf, 0, scale[i], 32, chardata);
z++;
}
}

}


STBTruetype.stbtt_PackEnd(pc);

chardata.position(0);


if a call to memory allocate is called at the same time from 2 different threads, will this likely be the cause of the error?
Should all memory allocation be done on a single thread?

This is strange as this issue didn't exist in the previous version (LWJGL 3.1.1 SNAPSHOT build 1), any thoughts on why this may be the case?
Title: Re: Errors when using newer version of LWJGL 3
Post by: Cornix on July 09, 2017, 14:47:21
Have you tried synchronising your calls to allocate? Does that change anything?
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 09, 2017, 14:59:27
not yet. I was hoping for a simpler solution. As I assume to synchronise all memory allocation I would have to 'lock' all areas over all possible code that uses memory allocation in order to prevent any conflicts, Im guessing that would take a while. I also assume it will take some guessing without insight into their implementation as to know which methods also allocate or free memory within them such as "stbtt_PackEnd"

I attached the console error output (I didnt include it all as it keeps going for a while before terminating)
Title: Re: Errors when using newer version of LWJGL 3
Post by: spasi on July 09, 2017, 15:50:35
Quote from: bobjob on July 09, 2017, 14:41:57if a call to memory allocate is called at the same time from 2 different threads, will this likely be the cause of the error?
Should all memory allocation be done on a single thread?

No and no. Memory allocators are thread-safe. Obviously there are situations that will blow up (using allocated memory after free, or doing a double-free), but it's not the allocator's problem. Almost all allocators have a fast-path when doing malloc/free in the same thread, but it's a performance optimization only.

Quote from: bobjob on July 09, 2017, 14:41:57ByteBuffer ttf = IOUtil.ioResourceToByteBuffer(name, 160 * 1024);

Are you holding on to this buffer while rendering? This is a common mistake when using stb_truetype. The buffer must not be freed, its data will be accessed by some stb_truetype functions, even after packing.
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 09, 2017, 16:02:10
I dont hold onto the bytebuffer.

the 'ByteBuffer ttf' is created using BufferUtils not MemoryUtils. So if anything holds a copy of it, it will retain the object. Note nothing requires the buffer to be passed to it later.

I do hold onto private STBTTPackedchar.Buffer chardata; which is allocated using:
STBTTPackedchar.malloc(scale.length * samples * 128);

I am still confused as to how this code works fine when this function is called on the main thread, but crashes only sometimes when loaded over a seperate thread.

I have made sure not to access any of the data until it is fully loaded. I'm also confused as to how a version change will allow for this bug.


Title: Re: Errors when using newer version of LWJGL 3
Post by: spasi on July 09, 2017, 16:25:22
Quote from: bobjob on July 09, 2017, 16:02:10I dont hold onto the bytebuffer.

Do you create an STBTTFontinfo to read metrics etc? If yes, then the buffer must stay alive while the STBTTFontinfo is used.

Quote from: bobjob on July 09, 2017, 16:02:10the 'ByteBuffer ttf' is created using BufferUtils not MemoryUtils.

...

I am still confused as to how this code works fine when this function is called on the main thread, but crashes only sometimes when loaded over a seperate thread.

I have made sure not to access any of the data until it is fully loaded. I'm also confused as to how a version change will allow for this bug.

It sounds like the crash is related to GC. Buffers allocated via BufferUtils are subject to GC, but due to how the JVM handles direct buffers, it might take a while (minimum 2 GC cycles) before the native memory is freed. This means that unrelated changes to your program, or doing things in different thread, or even a new JVM version, might affect when GC kicks in and when the memory is reclaimed. Which then affects when and how your program will crash (if at all).
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 09, 2017, 16:32:06
These are the classes I use to load the true type font.

import org.lwjgl.stb.STBTTAlignedQuad;
import org.lwjgl.stb.STBTTPackContext;
import org.lwjgl.stb.STBTTPackedchar;
import org.lwjgl.stb.STBTruetype;


Should I consider trying this for debugging:
download the LWJGL source (java)

edit the method:

public static long nmemAlloc(long size) {
        return ALLOCATOR.malloc(size);
}


and turn it into:

Object lock;
public static long nmemAlloc(long size) {
     synchronized(lock) {
         return ALLOCATOR.malloc(size);
     }
}

Title: Re: Errors when using newer version of LWJGL 3
Post by: spasi on July 09, 2017, 16:37:46
If you suspect a bug in jemalloc, you can revert to the system allocator with -Dorg.lwjgl.system.allocator=system.

To eliminate my suspicion about this being GC related, enable GC output with -XX:+PrintGC (or -Xlog:gc if you're on Java 9) and check if the crash happens immediately after a GC cycle.
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 09, 2017, 16:50:51
when I put in -Dorg.lwjgl.system.allocator=system
the problem goes away


Do you still want me to try the GC check?
Im using Java 8. Where do I put those options?

Title: Re: Errors when using newer version of LWJGL 3
Post by: spasi on July 09, 2017, 20:27:03
Ouch. That shouldn't happen.

First thing we can try is earlier jemalloc versions. Could you please try jemalloc.dylib from the LWJGL 3.1.0 and 3.1.1 releases? You can download it from here (https://www.lwjgl.org/download), using the "Click to browse..." functionality. Use -Dorg.lwjgl.system.jemalloc.libname=<path_to_jemalloc.dylib> to override the library to load and -Dorg.lwjgl.util.DebugLoader=true to verify that the correct one is being loaded.

If you could also share a minimal program that reproduces the issue, it would be very useful.
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 10, 2017, 08:01:11
I downloaded the dylib files via browsing from the download page:

3.1.2
[LWJGL] MemoryUtil accessor: MemoryAccessorUnsafe
[LWJGL] Loading library: /Volumes/Backup/lwjgl/3.1.2/libjemalloc.dylib
[LWJGL] Success
[LWJGL] MemoryUtil allocator: JEmallocAllocator

I can confirm the bug.

3.1.1

[LWJGL] Loading library: /Volumes/Backup/lwjgl/3.1.1/libjemalloc.dylib
[LWJGL] Success
[LWJGL] MemoryUtil allocator: JEmallocAllocator

I could NOT confirm the bug exists.

3.1.0
[LWJGL] Loading library: /Volumes/Backup/lwjgl/3.1.0/libjemalloc.dylib
[LWJGL] Success
[LWJGL] MemoryUtil allocator: JEmallocAllocator

I also could NOT observe the bug with this version

I will attempt to create a small program that that loads and unloads 2 seperate font files one on the main thread while the other loads on a background thread (both looping) to try reproduce the error.
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 10, 2017, 10:11:03
I was able to produce a simple program that loads 2 fonts at the same time.

QuoteHardware Overview:

  Model Name:   MacBook Pro
  Model Identifier:   MacBookPro12,1
  Processor Name:   Intel Core i5
  Processor Speed:   2.7 GHz
  Number of Processors:   1
  Total Number of Cores:   2
  L2 Cache (per Core):   256 KB
  L3 Cache:   3 MB
  Memory:   8 GB
  Boot ROM Version:   MBP121.0167.B24
  SMC Version (system):   2.28f7

The error would only occur when using the 3.1.2 version of jemalloc

Please note: this zip contains two ttf (font) files. It is a heavily stripped down version of my code. if its not clean enough I should be able to add comments and fix it. All of the relevant code should be in Program.java file and the draw2DOverlay() method body (inside Program.java)
Title: Re: Errors when using newer version of LWJGL 3
Post by: spasi on July 10, 2017, 19:18:50
Minor status update: I have reproduced it (only on macOS with jemalloc 3.1.2). Will post again when I have a better understanding of the issue.
Title: Re: Errors when using newer version of LWJGL 3
Post by: spasi on July 10, 2017, 21:35:11
Looks like building jemalloc without --enable-tls and --enable-lazy-lock fixes it.
Title: Re: Errors when using newer version of LWJGL 3
Post by: spasi on July 21, 2017, 19:58:41
Sorry for the delay, 3.1.3 #5 is now available with a, hopefully, fixed jemalloc build. Could you please give it a try?
Title: Re: Errors when using newer version of LWJGL 3
Post by: bobjob on July 22, 2017, 06:39:59
Brilliant, I was not able to observe the bug in that latest version.

Thanks spasi. Im always impressed by the way you have a nack for fixing code.