Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (494)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  GC causing massive delay  (Read 2324 times)
0 Members and 1 Guest are viewing this topic.
Offline Quarry
« Posted 2013-08-02 21:31:12 »

http://pastebin.com/eXWS0qrc

The output above is;

1  
System.out.println(((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024));


and as you can see GC occurs at 1526 and right at that moment my frames drop from solid 60 to 35

I'm using -XX:+UseConcMarkSweepGC as my GC, I tried other types as well but none of them really helped me

Can anyone help me with this?
Offline Redocdam

Senior Member


Medals: 17



« Reply #1 - Posted 2013-08-02 22:00:21 »

Concurrent garbage collection seems to be the way to go. At least it works well for me. You can try tweaking the memory settings a bit, but that's likely not going to solve your overall problem.

Basically what happens is the GC thread causes everything else to pause while it goes through and cleans house. Adding a large chunk of memory just makes its pauses further apart, but last longer.

The real way to fix this is by profiling for your data build up. I use Java VisualVM to help profile and track down bottle necks.
http://docs.oracle.com/javase/6/docs/technotes/guides/visualvm/

What's likely occurring is you're creating a lot of new classes during your looping. One of the best ways to handle this is to reuse objects which can be reused. However, I recommend running your code through the Profiler first so you can get a break down of which classes are building up the most data.

Offline ClickerMonkey

JGO Coder


Medals: 20


Game Engineer


« Reply #2 - Posted 2013-08-02 22:09:14 »

Stop calling new inside of loops.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Quarry
« Reply #3 - Posted 2013-08-02 22:33:43 »



Does this basically mean that I have too much buffer objects and float arrays? Also what's up with cleaner?
Offline HeroesGraveDev

JGO Kernel


Medals: 250
Projects: 11
Exp: 2 years


┬─┬ノ(ಠ_ಠノ)(╯°□°)╯︵ ┻━┻


« Reply #4 - Posted 2013-08-02 22:52:35 »

If you aren't already, you could try using mapped buffers.

Offline Quarry
« Reply #5 - Posted 2013-08-02 23:08:23 »

I have no idea about the ByteBuffers, the only case I'm using them is for loading textures (LWJGL)
Offline HeroesGraveDev

JGO Kernel


Medals: 250
Projects: 11
Exp: 2 years


┬─┬ノ(ಠ_ಠノ)(╯°□°)╯︵ ┻━┻


« Reply #6 - Posted 2013-08-02 23:22:24 »

I have no idea about the ByteBuffers, the only case I'm using them is for loading textures (LWJGL)

I use this method:

The VBO must be bound before calling this method.

1  
2  
3  
4  
5  
6  
public static FloatBuffer mapBuffer(int length)
{
   GL15.glBufferData(GL15.GL_ARRAY_BUFFER, length << 2, GL15.GL_STATIC_DRAW);
   ByteBuffer buf = GL15.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY, length << 2, null);
   return buf.order(ByteOrder.nativeOrder()).asFloatBuffer();
}


Returns a mapped float buffer.

Offline Quarry
« Reply #7 - Posted 2013-08-02 23:32:46 »

Here's my VertexBuffer object, I never change the contents of them (and I only have one atm) so I really doubt they are the stupid amount of float[] and FloatBuffers

http://pastebin.com/6faTZ21N

My guess is that the float[] and FloatBuffers are from my matrix/vector classes

Here's Main.java

http://pastebin.com/CjnMAQFF

and Renderer.java

http://pastebin.com/8Lwg9ftw
Offline ClickerMonkey

JGO Coder


Medals: 20


Game Engineer


« Reply #8 - Posted 2013-08-02 23:47:30 »

In your renderer, in asFlippedFloatBuffer, cache a ByteBuffer and only use ONE (make it static and what not).

You call that ALOT and each time it creates a DirectByteBuffer... which allocates a chunk of memory outside the JVM... and when the JVM sees that it's not in use it cleans it and removes it. This could take time and they could add up.

Offline Redocdam

Senior Member


Medals: 17



« Reply #9 - Posted 2013-08-03 00:13:42 »

You're not alone in this problem. I'm fairly certain you're running up against the exact problem I encountered, because I built my own objects for handling matrices and vectors.

Also like you, I figured arrays would be the most natural way of handling this. Now you can still do it with arrays if you really want, but here's what I found:
Arrays are objects, so every time you create one of those, you end up with the potential for garbage. This problem is compounded when you do things like set the Matrix by using a new float[] or have it return a new float[].

You may be wondering how you handle passing around matrices and stuff without referencing the original matrix. I mean if you pass a matrix to a method and have it mangle the bastard, it's going to destroy the original copy you wanted to keep, since Java behaves like objects are pass by reference (pedantic note: My understanding is Java is considered pass by value).

The answer comes from a seemingly unlikely place. Since Java handles objects like references and primitives as values, it's actually easier to to set your Matrices and Vectors to contain primitives. For me it felt like this goes against what you're taught in programming 101. But like everything with code, it's always subjective to the what you need it for.

So here's what I did:
I changed my matrices to be something like
1  
2  
3  
4  
   public float c00 =1;   public float c10 =0;   public float c20 =0;   public float c30 =0;
   public float c01 =0;   public float c11 =1;   public float c21 =0;   public float c31 =0;
   public float c02 =0;   public float c12 =0;   public float c22 =1;   public float c32 =0;
   public float c03 =0;   public float c13 =0;   public float c23 =0;   public float c33 =1;

And of course the same thing as with the vectors.
Now you can do all the multiplication and what not by passing matrices into other matrices and then do your operation using the primitives.
Here's an example of setting a matrix from another matrix
1  
2  
3  
4  
5  
6  
7  
   public void setMatrix(Matrix4 matrix){ //Set the matrix
     
      this.c00 = matrix.c00;   this.c10 = matrix.c10;   this.c20 = matrix.c20;   this.c30 = matrix.c30;  
      this.c01 = matrix.c01;   this.c11 = matrix.c11;   this.c21 = matrix.c21;   this.c31 = matrix.c31;
      this.c02 = matrix.c02;   this.c12 = matrix.c12;   this.c22 = matrix.c22;   this.c32 = matrix.c32;
      this.c03 = matrix.c03;   this.c13 = matrix.c13;   this.c23 = matrix.c23;   this.c33 = matrix.c33;
   }

This way you avoid linking two matrices together by reference. The above method will create an entirely new set of values from the matrix which was passed in.

This actually turns out to be quite fast. I was a little concerned that using primitives like this would eventually lead slowing things down. So I did some testing and it turns out Java is very fast at setting primitive values. And since you'll only handle up to 16 values, you're not losing out by skipping arrays.
It also makes accessing individual cells kind of nice.

Conclusion:
I started down the rabbit hole of correcting my math, because I encountered the stuttering effect due to garbage collection. Before I fixed everything, I noticed my used memory was accumulating faster than an ex-wife could amass debt with her ex-husbands credit card. It was knocking over hundreds in seconds.
Now that I've cleaned the math up and reused objects like matrices, it takes a couple seconds before I even see it kick over 1 MB. I imagine you'll encounter the same.

And like the others have said before me, reusing your Buffers will also go a long way.

In the end, I think most of us go through this at one point or another. So don't let it get you down.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Quarry
« Reply #10 - Posted 2013-08-03 14:41:30 »

In your renderer, in asFlippedFloatBuffer, cache a ByteBuffer and only use ONE (make it static and what not).

You call that ALOT and each time it creates a DirectByteBuffer... which allocates a chunk of memory outside the JVM... and when the JVM sees that it's not in use it cleans it and removes it. This could take time and they could add up.

Could you give me an example on that as my buffers are varying in sizes? I was thinking of using a HashMap to store buffers in (if a key doesn't have a value, generate it - if a key has a value, clear and re-insert values)
Offline ClickerMonkey

JGO Coder


Medals: 20


Game Engineer


« Reply #11 - Posted 2013-08-03 14:56:31 »

Remove your three methods toFloatArray, asFlippedFloatBuffer, and asFlippedByteBuffer and replace with this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
        ByteBuffer cachedBuffer = BufferUtils.createByteBuffer(4096);

        private static FloatBuffer asFlippedFloatBuffer(Matrix4 matrix4) {
                final ByteBuffer bb = cachedBuffer;
                bb.clear();
                for (int i = 0; i < 16; i++) {
                        bb.putFloat( (float)matrix4.mat[i] );
                }
                bb.flip();
                return bb.asFloatBuffer();
        }
 
        private static ByteBuffer asFlippedByteBuffer(byte[] arr) {
                final ByteBuffer bb = (arr.length > cachedBuffer.capacity() ? BufferUtils.createByteBuffer(arr.length) : cachedBuffer);
                bb.clear();
                bb.put(arr);
                bb.flip();
                return bb;
        }


I guessed 4096 was a large enough ByteBuffer... if you are sending more than matrices (like vertex data for example) up it to 65536 or something (64kb isn't really that much).

Offline Quarry
« Reply #12 - Posted 2013-08-03 18:41:04 »

Daaaaaamn... that is so amazing! Thanks a lot!
Offline ralphchapin

Junior Member


Medals: 3
Projects: 1



« Reply #13 - Posted 2013-08-03 19:00:43 »

I don't do the fast graphics like you do; I tend more towards the turn-based, and my problems tend to be more about checking who's near whom and what's the shortest path to somewhere.  (And I write business software too.)  And the GC problem usually shows ups as an out-of-memory exception (despite lots of free memory) rather than a slowdown.  But your problems and mine are likely related, so:

The key word is Fragmentation.  It's been a long time since I've had a program hesitate while the GC runs.  The GC that comes from Oracle with the JVM does a superb and invisible job.  I don't think even you should notice that it's running, no matter how many new objects you create.  But if you create large objects (arrays), then the GC has to look harder to find the contiguous space for them.  When you've created--and freed--a bunch, your free memory is mostly large-object-sized chunks with, perhaps, pieces taken out for small new allocations.  Now if you try to allocate a new large object, there's no space quite big enough or contiguous enough.  Your memory is fragmented.

The GC will work frantically to move allocated memory around to turn smaller free chunks into bigger chunks.  If your program used memory at a leisurely pace (if your game ran 10 times slower), you'd never notice a problem.  As it is, you are most likely seeing the resultant slowdown.

If you ignored it and let it get worse, eventually the GC would prefer throwing an exception to embarrassing itself with such abysmal performance.  (That's what usually happens to me.)

My solution is to avoid arrays and things that use them like HashMaps and ArrayLists and use TreeMaps and LinkedLists instead.  This would, most often, not work for you; arrays really are much faster than, say LinkedLists, even for sequential reading.  So my answer to your problem is, like most of the other ones:  keep your arrays as small as you can and reuse them.  The new arrays are the problem.  (I'm putting this answer here to explain why this is happening; the solution's been given several times over.)

(Also, making all your arrays the same size might help.  The classic way to get this problem is to add millions of items to an ArrayList.  Each time the ArrayList resizes, it needs a bigger array.  Once the original memory is used up, free memory is fragmented into many large blocks, but none of them big enough for the next allocation.)
Offline Quarry
« Reply #14 - Posted 2013-08-03 19:03:33 »

Thanks for the info, one problem I noticed is that I now have an increased amount of int[] which weren't there before

EDIT: I accidentally ran sampling instead of profiling, it's okay now
Offline sproingie

JGO Kernel


Medals: 202



« Reply #15 - Posted 2013-08-05 16:21:19 »

If the bulk of the memory usage is from DirectByteBuffers, then heap fragmentation isn't so much the issue, or rather not the java heap anyway.  Every direct buffer you allocate has to be malloc()'d individually from the native heap, and creates a PhantomReference and a Cleaner object that will free() it when it goes out of scope.  Each one, individually.  In short, while using direct buffers is ridiculously fast, allocating them is a very heavyweight operation.  You're meant to reuse them as much as possible.

ArrayList won't reallocate every time you resize it, and will pre-extend itself by quite a bit.  However, it actually tends to err on the side of pre-extending by too much which puts additional pressure on the GC for space you don't need or use.  If you have a good estimate on the number of items you're putting into a collection, it's always a good idea to instantiate it with the size hint and not the default of 10.
Online Riven
« League of Dukes »

JGO Overlord


Medals: 796
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #16 - Posted 2013-08-06 09:35:34 »

ArrayList won't reallocate every time you resize it, and will pre-extend itself by quite a bit.  However, it actually tends to err on the side of pre-extending by too much which puts additional pressure on the GC for space you don't need or use.  If you have a good estimate on the number of items you're putting into a collection, it's always a good idea to instantiate it with the size hint and not the default of 10.
and use trimToSize to free up memory, if you're not too sure what data size you're dealing with upfront, and are running low on free memory. ArrayList at most allocates 50% too much memory (doubling the backing array every time) which is normally not enough to worry about. (C devs, will scream at me, I'll look the other way Smiley)

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline ralphchapin

Junior Member


Medals: 3
Projects: 1



« Reply #17 - Posted 2013-08-07 00:42:53 »

The problem I was referring to--whether or not the OP's problem is another matter--is the too-rapid allocation and deallocation of large blocks of memory; it's got little to do with using a lot of memory or wasting memory.  The most typical symptom is getting an out-of-memory exception with 90% of memory free.  The simplest way to do it is with something like:
1  
2  
    ArrayList  array = new ArrayList();
    while (true)  { array.add( something ); }

If the optimizers don't interfere, this will, of course, throw an out-of-memory exception.  What is unusual is that when it does a lot of memory will still be free.  (There must be a dozen questions about this on StackOverflow.)  The reason for the OOME is not that there's no memory left, but that the GC is taking too long to merge free blocks and gives up rather than slow down too much.

Most people see the OOME and wonder why.  I think game writers are more apt to see the slowdown and wonder why.

Reducing the size of allocated memory helps a lot.  Reusing big arrays helps a lot.  Doing lots of other work between allocations (giving the GC thread time to do it's job) helps, too.
Online Riven
« League of Dukes »

JGO Overlord


Medals: 796
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #18 - Posted 2013-08-07 07:53:57 »

@relphchapin

I was surprised by your findings and was absolutely sure you were absolutely wrong Smiley

The GC strategies (since about 15 years) don't even merge free memory blocks. Garbage collectors don't collect garbage, so to speak, they copy live objects into a new memory block, completely ignoring free space. When everything is copied, the whole original space is declared free for future use. That means that fragmentation is simply not an issue with Java objects and arrays - only for direct buffers, as they are backed by malloc/free algorithms.

Equally, the GC doesn't throw its hands into the air and call it quits when it has to work really hard. There is one case, however, and that is that when the GC concludes that it is collecting garbage over 99% of the time, for an extended period (say, minutes), it will conclude it's infeasible to continue running. This doesn't happen in practice, unless you're paging massive amounts of memory to disk and back, at which point your game/service is dead in the waters anyway.



On to your examples:

1  
2  
3  
4  
5  
6  
7  
List<?> list = new ArrayList<>();
for (int i = 0; true; i++) {
   if (i % (1024 * 1024) == 0)
      System.out.println("i=" + (i / 1024 / 1024));
      list.add(null);
   }
}
1  
Output: reaches ~150M elements on a 2GB heap in 5sec


1  
2  
3  
4  
5  
6  
7  
List<?> list = new LinkedList<>();
for (int i = 0; true; i++) {
   if (i % (1024 * 1024) == 0)
      System.out.println("i=" + (i / 1024 / 1024));
      list.add(null);
   }
}
1  
Output: reaches ~67M elements on a 2GB heap in 61sec


So your workaround results into slower code that fails earlier. It shouldn't be advised.



1  
2  
System.out.println(System.getProperty("java.version"));
System.out.println(System.getProperty("java.vm.version"));
1  
2  
1.7.0_25
23.25-b01

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline sproingie

JGO Kernel


Medals: 202



« Reply #19 - Posted 2013-08-07 16:10:54 »

The GC will give up if it's unable to free space for allocation while meeting its pause time and throughput goals.   As usual, the Java GC Tuning doc is a handy reference for the various knobs that control GC throughput among other things.  It's of little help when it comes to direct buffers though, since those are allocated much more primitively and slowly on a different heap.
Offline ralphchapin

Junior Member


Medals: 3
Projects: 1



« Reply #20 - Posted 2013-08-08 03:21:43 »

@Riven

I haven't tried this recently, and when I last had the problem I was trying to do something else completely.  Still, I've heard of enough other people with the problem that I doubt it's gone away.  I am beginning to wonder if my ArrayList Add test does much to demonstrate it.

I would suggest adding a new object rather than null to the array.  What you've got will, if I still understand ArrayList, fill memory consecutively with arrays, each 50% larger than the previous.  All but the last two will be freed, and the next to last one will usually be freed.  When allocations hits the end of available memory, they can easily go back to the start and reuse what's there.  Adding actual objects will put those objects between each array.  Now the GC has some real work to do.  I can't guarantee a proper out-of-memory exception with 90% of memory still free, but you should see something of interest.

It seems to me that fragmentation still must be an issue.  To allocate space for a large array, you need a bunch of contiguous memory blocks with nothing in them.  With allocated bits of memory scatter through them, that means a lot of copying.

LinkedLists are slow memory hogs, but they only ask the GC to do a tiny amount of work at a time.

And its probably time for me to go read the tuning doc.... Smiley
Offline Grunnt

JGO Wizard


Medals: 68
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #21 - Posted 2013-08-08 08:21:41 »

I found this an enlightening discussion, and I would like to learn a bit more about the inner workings of garbage collection in the JVM. Do you guys have suggestions for "further reading"?

I do know about (and am reading) Oracle's GC tutorials and Oracle's info about HotSpot GC.

Online Riven
« League of Dukes »

JGO Overlord


Medals: 796
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #22 - Posted 2013-08-08 08:25:09 »

When allocations hits the end of available memory, they can easily go back to the start and reuse what's there.  Adding actual objects will put those objects between each array.  Now the GC has some real work to do.
You really have to let the idea of costly merges of free-lists go. Inserting objects between arrays really won't matter, due to the nature of the GC algorithms, as explained earlier, they copy alive objects and arrays to a new memory block, meanig that there simply are no free lists to merge.


LinkedLists are slow memory hogs, but they only ask the GC to do a tiny amount of work at a time.
They actually require the GC to do a lot of work, because it has to trace extremely deep object graphs of reachable objects, which is what will slow everything down tremendously for every single garbage collection, even when all objects reside in Eden.


Just test it yourself, it only takes 1 minute to test (and invalidate) your C-heap inspired theories.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline ralphchapin

Junior Member


Medals: 3
Projects: 1



« Reply #23 - Posted 2013-08-10 19:38:23 »

@Riven:  You're right.  I have seen big-array problems;whether that was an old GC or whether I need a fancier test to reproduce it I don't know.

I ran the thing on an antique machine with a 250MB heap and a single core.  I added an actual object (an 8 character string, created with "new"--just using quotes gave me the same results as using null).  Using the object slows down the ArrayList so it's only about half again as fast as the linked list and can only hold twice as much before the out-of-memory error.  (Without it, my results were like yours, scaled down by a factor of 8.  I printed a message and time every 131072 (1024X128) lines.

The results between the two lists were amazingly similar.  The ArrayList needed 20 milliseconds between rows and the LinkedList 30.  (Its a slow machine, and the smallest measurable time interval is 10 milliseconds.)  About every ten to 12 messages, the time needed spiked to 500 to 2000 ms, getting larger as the program ran.  I looked to me like the program was doing repeated garbage collections.  These would be needed for the ArrayList, but in the case of the LinkedList, until the last one there was plenty of free memory and, at no point, was any memory freed!

As you noted, arrays take less time in gc, even when there is array space to be collected and no LinkedList space to be collected.

I'm not sure what to make of all this.  It seems to slow down code that doesn't free large arrays without helping those that do.  But it is interesting.
Online Riven
« League of Dukes »

JGO Overlord


Medals: 796
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #24 - Posted 2013-08-11 00:35:02 »

You really have to drop the concept of collecting garbage and freeing memory. That's not what a garbage collector does Smiley

Think of it as a room with gadgets, toys, empty pizza boxes and dead rats. Mom comes in, takes handful of toys and gadgets, puts them in brother's room, then locks your room. Whatever filth was there is out of reach and can be completely ignored. (if we go further, the analogy breaks apart... let's say uncle bob effortlessly atomizes whatever is left in your room, and pumps it in your 3d printer reservoir, for you to print new pizza boxes, which attract dead rats, aight!)

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline HeroesGraveDev

JGO Kernel


Medals: 250
Projects: 11
Exp: 2 years


┬─┬ノ(ಠ_ಠノ)(╯°□°)╯︵ ┻━┻


« Reply #25 - Posted 2013-08-11 00:59:41 »

Think of it as a room with gadgets, toys, empty pizza boxes and dead rats. Mom comes in, takes handful of toys and gadgets, puts them in brother's room, then locks your room. Whatever filth was there is out of reach and can be completely ignored. (if we go further, the analogy breaks apart... let's say uncle bob effortlessly atomizes whatever is left in your room, and pumps it in your 3d printer reservoir, for you to print new pizza boxes, which attract dead rats, aight!)

That has to be the best analogy I've ever read. Grin             

Offline Spasi
« Reply #26 - Posted 2013-08-11 07:41:08 »

I found this an enlightening discussion, and I would like to learn a bit more about the inner workings of garbage collection in the JVM. Do you guys have suggestions for "further reading"?

Java Garbage Collection Distilled
Understanding Garbage Collection
G1: One Garbage Collector To Rule Them All
Garbage First Garbage Collector Tuning
Offline relminator
« Reply #27 - Posted 2013-08-11 15:30:55 »

You really have to drop the concept of collecting garbage and freeing memory. That's not what a garbage collector does Smiley

Think of it as a room with gadgets, toys, empty pizza boxes and dead rats. Mom comes in, takes handful of toys and gadgets, puts them in brother's room, then locks your room. Whatever filth was there is out of reach and can be completely ignored. (if we go further, the analogy breaks apart... let's say uncle bob effortlessly atomizes whatever is left in your room, and pumps it in your 3d printer reservoir, for you to print new pizza boxes, which attract dead rats, aight!)
Very nice explanation.  Thanks!

So if the gc does not free garbage collected objects, what happens to the collected garbage?  Does it just stay there infinitely until program closes?
Offline Grunnt

JGO Wizard


Medals: 68
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #28 - Posted 2013-08-11 19:12:10 »

Great, thanks Spasi! I'm reading it now, it's good background info.

Online Riven
« League of Dukes »

JGO Overlord


Medals: 796
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #29 - Posted 2013-08-12 08:49:57 »

So if the gc does not free garbage collected objects, what happens to the collected garbage?  Does it just stay there infinitely until program closes?
It's a block of memory containing meaningless ones and zeroes. Eventually the block of memory will be overwritten with meaningful ones and zeros. (new objects)

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Pages: [1] 2
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Dwinin (22 views)
2014-09-12 09:08:26

Norakomi (55 views)
2014-09-10 13:57:51

TehJavaDev (68 views)
2014-09-10 06:39:09

Tekkerue (33 views)
2014-09-09 02:24:56

mitcheeb (55 views)
2014-09-08 06:06:29

BurntPizza (39 views)
2014-09-07 01:13:42

Longarmx (24 views)
2014-09-07 01:12:14

Longarmx (30 views)
2014-09-07 01:11:22

Longarmx (30 views)
2014-09-07 01:10:19

mitcheeb (37 views)
2014-09-04 23:08:59
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!