Java-Gaming.org Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (799)
Games in Android Showcase (237)
games submitted by our members
Games in WIP (865)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Java2D fillRect() memory leak  (Read 4427 times)
0 Members and 1 Guest are viewing this topic.
Offline DrewLols

Senior Devvie


Medals: 4
Projects: 1


Noob going through metamorphosis...


« Posted 2015-04-23 04:58:33 »

Here is a bit of sample code I have from a map-making GUI I'm working on.
The class containing it is called TileNode, which stores a Tile and other information.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
   /**
    * Draws the TileNode
    * @param g Graphics context to draw to
    * @param x Location X
    * @param y Location Y
    */

   public void draw(Graphics2D g, int x, int y)
   {  
      // Draw the tile itself
      tile.draw(g, x, y);
     
      // If selected, highlight area of tile
      if(state == TileState.SELECTED)
      {
         Composite oldC = g.getComposite();
         g.setColor(Color.WHITE);
         g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
         g.fillRect(x, y, tile.getWidth(), tile.getHeight());
         g.setComposite(oldC);
      }
   }


This code is supposed to highlight a tile when it is in the selected state.
When I run my program, and I continue calling this code, my memory climbs very very fast.  The strange thing, when I don't call g.fillRect(), or I set my alpha composite's alpha to 1, this does not happen.  The graphics component is eventually disposed of, but that does not seem to help.  I am very confused...

Any insight?

Edit:  It also makes no difference if I call g = (Graphics2D)g.create() at the top, and g.dispose() at the bottom of the function.  Still memory hungry.

Did you know that 90% of statistics are wrong?
Offline trollwarrior1
« Reply #1 - Posted 2015-04-23 05:22:06 »

Do you get out of memory error eventually?
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #2 - Posted 2015-04-23 05:35:39 »

It could be simply that the GC didn't deem the heap large enough to make a sweep yet. How large was the supposed leak?

If it is large, then run under jvisualvm and profile the heap usage. Look at what types are being allocated.

Some other musings:

Of note is that AlphaComposite.getInstance(int, float) does allocate on each call, although that isn't a leak.

For fillRect:

I would start from here (perhaps use the applicable jdk version)
Then find out what type of PixelFillPipe is being used:
System.out.println(g.getClass().getDeclaredField("fillpipe").get(g));


Then investigate that impl's fillRect. For instance an app of mine reports a ValidatePipe. This calls validatePipe() on what turns out to be a BufImgSurfaceData (also found via reflection), which does not override the default SurfaceData validatePipe(), which is convenient. The validatePipe() method can potentially go in many directions, that depends heavily on your surrounding code, so I stopped there, but hopefully you get the idea.

EDIT: More reflection:

1  
2  
3  
4  
5  
6  
// causes ValidatePipe.validatePipe() to set g's actual pipe
g.getClass().getMethod("validatePipe").invoke(g);
           
// now we get sun.java2d.pipe.LoopPipe instead of ValidatePipe, ha!
Object fillpipe = g.getClass().getDeclaredField("fillpipe").get(g);
System.out.println(fillpipe);


LoopPipe calls into native code for fillRect, so that's the end of the line there unless you want to find and look into the natives for that.

---------------

Edit 2 because procrastinating sleep:

Forgot to observe what happens when setComposite is actually called, LoopPipe is not what is used:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
           
System.out.println(g);
           
// causes ValidatePipe.validatePipe() to set g's actual pipe
g.getClass().getMethod("validatePipe").invoke(g);
           
Object fillpipe = g.getClass().getDeclaredField("fillpipe").get(g);
System.out.println(fillpipe); // PixelToShapeConverter
           
Field[] fillpipe_fields = fillpipe.getClass().getDeclaredFields();
for (Field f : fillpipe_fields)
    f.setAccessible(true);
           
Object outpipe = fillpipe_fields[0].get(fillpipe);
System.out.println(outpipe); // SpanShapeRenderer, calls renderRect which calls CompositePipe stuff
           
Field[] outpipe_fields = outpipe.getClass().getDeclaredFields();
for (Field f : outpipe_fields)
   f.setAccessible(true);
           
Object compositepipe = outpipe_fields[0].get(outpipe);
System.out.println(compositepipe); // AlphaPaintPipe


AlphaPaintPipe methods called from SpanShapeRenderer$Composite include some suspicious comments like this:

Quote
// Avoid creating new WeakReference if possible

-------------------

Edit 2.5:

Sigh, turns out it wasn't a leak.  I shrinked the heap size, and found that memory peaked at about 140mb.  Still uses a lot of cpu power, though.  My drawing code is definitely open to optimization, of course.  Thanks for the tips, though

That's pretty much what I expected.  Tongue

-------------------

Again jvisualvm might be good for profiling method calls, if just to see what methods are being called.

GrepCode is good for this, take note of the small down arrows on methods and types, they link to derived types/methods, which is excellent for this kind of investigation.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline DrewLols

Senior Devvie


Medals: 4
Projects: 1


Noob going through metamorphosis...


« Reply #3 - Posted 2015-04-23 06:27:15 »

Sigh, turns out it wasn't a leak.  I shrinked the heap size, and found that memory peaked at about 140mb.  Still uses a lot of cpu power, though.  My drawing code is definitely open to optimization, of course.  Thanks for the tips, though

Did you know that 90% of statistics are wrong?
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #4 - Posted 2015-04-23 06:35:00 »

Well at least it's not a leak.

I do like to dive into the j2d underpinnings from time to time, but not too often, considering how nightmarish-ly complex it is.
I'd like to somehow try to write a fast path (read: way fewer allocations) for simple usage, but it's just too insane. All I've managed is some tricks to allow lots of setColor calls with mutable color objects, but nothing useful for blitting, etc.
Offline DrewLols

Senior Devvie


Medals: 4
Projects: 1


Noob going through metamorphosis...


« Reply #5 - Posted 2015-04-23 06:43:02 »

It still uses far too more memory than it should.  This problem doesn't seem to happen when drawing images.  I know this sounds stupid, but prehaps I should just generate a light buffered image and draw that instead of drawing a translucent rect.  I don't have this memory/cpu overkill when drawing images, but god FORBID I draw a translucent rectangle...  I'm talking 140 mb+ here.  We shall see...

Did you know that 90% of statistics are wrong?
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #6 - Posted 2015-04-23 06:48:05 »

Yep, it's pretty bad. Whenever I use j2d and want bearable/as good as I can get performance I try to not call any Graphics.draw/fill methods other than drawImage, at least in the hot areas.
Past experience is that writing your own/stealing pixel-pushing routines in a bufferedimage can beat SunGraphics2D, although good luck with alpha compositing.

Edit: I forgot about a nifty feature for posterity: the -Dsun.java2d.trace=log flag. It logs the final drawing methods beings used.
Offline nsigma
« Reply #7 - Posted 2015-04-23 08:12:29 »

Past experience is that writing your own/stealing pixel-pushing routines in a bufferedimage can beat SunGraphics2D, although good luck with alpha compositing.

Or check out this thread with code for fast software blend modes.

Praxis LIVE - hybrid visual IDE for (live) creative coding
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 486
Exp: 7 years



« Reply #8 - Posted 2015-04-23 08:15:46 »

Oh I've had that bookmarked for a while.  Pointing
Offline DrewLols

Senior Devvie


Medals: 4
Projects: 1


Noob going through metamorphosis...


« Reply #9 - Posted 2015-04-23 17:46:57 »

Thought I should mention that I can actually draw a transluscent white box by setting the color to a translucent one.

ie: g.setColor(new Color(1, 1, 1, 0.5f));

Rather than setting the AlphaComposite.  Guess that won't help you draw a translucent image, but that's not what I'm trying to do.
Perhaps I'm just imagining things, but I think it yields a slightly better performance.

My code is hardly optimized.  Whenever a graphical change happens to the tileset I'm rendering, it re-renders the entire tileset with all the tiles.  This results in a lot of draw calls when I make a selection with the mouse and drag it all over the place.  I suppose I could optimize it to only render the changed parts.  And If I'm crazy like you said, I could try to push my own pixels.  I'm taking an intro graphics course atm, so I don't think making a blending algorithm would be TOO difficult after building my own ray tracer.  Just have to figure out the millions of indirections that there are in Java2D.

I get the feeling that Java2D was specifically made for awt, swing, and Java GUI in general, since Components in a GUI don't repaint that often.  In my GUI, this unoptimized part does if you drag the mouse all the time.

Did you know that 90% of statistics are wrong?
Pages: [1]
  ignore  |  Print  
 
 

 
Riven (201 views)
2019-09-04 15:33:17

hadezbladez (4921 views)
2018-11-16 13:46:03

hadezbladez (1814 views)
2018-11-16 13:41:33

hadezbladez (5196 views)
2018-11-16 13:35:35

hadezbladez (1025 views)
2018-11-16 13:32:03

EgonOlsen (4389 views)
2018-06-10 19:43:48

EgonOlsen (5230 views)
2018-06-10 19:43:44

EgonOlsen (2973 views)
2018-06-10 19:43:20

DesertCoockie (3876 views)
2018-05-13 18:23:11

nelsongames (4308 views)
2018-04-24 18:15:36
Java Gaming Resources
by philfrei
2019-05-14 16:15:13

Deployment and Packaging
by philfrei
2019-05-08 15:15:36

Deployment and Packaging
by philfrei
2019-05-08 15:13:34

Deployment and Packaging
by philfrei
2019-02-17 20:25:53

Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08

Deployment and Packaging
by gouessej
2018-08-22 08:03:45
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!