The attached sample program produces a memory leak when the screen lock is active on windows.
package com.thalesgroup.de.gsr.test.testplugin.javafx.regionimage;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;
import javafx.embed.swt.FXCanvas;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.scene.paint.Color;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
/**
* @author Jochen Mönch
*/
public class StandaloneTestJavaFX {
private static final Logger log = Logger.getLogger( StandaloneTestJavaFX.class );
private static final int WIDTH = 1280;
private static final int HEIGHT = 1000;
private FXCanvas fxCanvas;
public Color color = Color.rgb( 255, 0, 0 );
private Canvas canvas;
private PixelFormat<ByteBuffer> pixelFormat;
private byte[] imageData;
private int cycles = 0;
private long lastCycleRateLog = System.currentTimeMillis();
private int overallCycles = 0;
private final byte blueByte;
private final byte greenByte;
private final byte redByte;
private final byte alphaByte;
private long lastUpdate = System.currentTimeMillis();
private long lastAdd = System.currentTimeMillis();
private final List<Rectangle2D> pendingRectangles = new LinkedList<Rectangle2D>();
private boolean changed = false;
private boolean stop = false;
private Shell shell;
public static void main(final String[] args) {
BasicConfigurator.configure();
StandaloneTestJavaFX test = new StandaloneTestJavaFX();
test.run();
}
/**
* Constructor. Opens Gui.
*
* @param parent
*/
public StandaloneTestJavaFX() {
createShell();
createGUI( shell );
createImageData();
blueByte = (byte) (Math.round( color.getBlue() * 255 ) & 0xff);
greenByte = (byte) (Math.round( color.getGreen() * 255 ) & 0xff);
redByte = (byte) (Math.round( color.getRed() * 255 ) & 0xff);
alphaByte = (byte) 0xff;
}
public void run() {
shell.open();
new Thread( new Runnable() {
@Override
public void run() {
while( !stop ) {
doWork();
}
}
}, "FXPainter" ).start();
while( !shell.isDisposed() ) {
if( !shell.getDisplay().readAndDispatch() ) {
shell.getDisplay().sleep();
}
}
}
private void createShell() {
shell = new Shell( Display.getDefault() );
shell.setSize( WIDTH, HEIGHT );
shell.setLayout( new FillLayout() );
}
private void createGUI(final Composite parent) {
fxCanvas = new FXCanvas( parent, SWT.NONE );
Group rootGroup = new Group();
rootGroup.setCache( false );
Scene scene = new Scene( rootGroup, Color.TRANSPARENT );
fxCanvas.setScene( scene );
canvas = createCanvas();
rootGroup.getChildren().add( canvas );
}
private void createImageData() {
imageData = new byte[WIDTH * 4 * HEIGHT];
pixelFormat = PixelFormat.getByteBgraInstance();
for( int y = 0; y < HEIGHT; y++ ) {
for( int x = 0; x < WIDTH; x++ ) {
int startIdx = getStartIndex( y, x );
imageData[startIdx] = 0x0;
imageData[startIdx + 1] = 0x0;
imageData[startIdx + 2] = 0x0;
imageData[startIdx + 3] = 0x0;
}
}
}
private Canvas createCanvas() {
Canvas canvas = new Canvas();
canvas.setCache( true );
canvas.setWidth( WIDTH );
canvas.setHeight( HEIGHT );
canvas.setVisible( true );
return canvas;
}
private void doWork() {
final long now = System.currentTimeMillis();
if( now - lastAdd >= 1 ) {
addNewData( 1000 );
lastAdd = now;
}
if( now - lastUpdate >= 50 ) {
updateContent( (int) Math.round( 255.0 / 30.0 ) );
lastUpdate = now;
}
if( !fxCanvas.isDisposed() ) {
if( now - lastCycleRateLog > 1000 ) {
double timeSpend = (now - lastCycleRateLog) / 1000.0;
double cycleRate = cycles / timeSpend;
log.info( "CycleRate: " + cycleRate + ", total cycles: " + cycles );
lastCycleRateLog = now;
cycles = 0;
}
paintContent( overallCycles );
cycles++;
overallCycles++;
} else {
stopWork();
}
}
private void stopWork() {
stop = true;
}
private void addNewData(final int numRects) {
synchronized( imageData ) {
for( int i = 0; i < numRects; i++ ) {
int x = (int) Math.round( Math.random() * (WIDTH - 5) );
int y = (int) Math.round( Math.random() * (HEIGHT - 5) );
pendingRectangles.add( new Rectangle2D( x, y, 5, 5 ) );
}
}
}
private void updateContent(final int decreaseAlphaBy) {
synchronized( imageData ) {
adjustAlpha( imageData, decreaseAlphaBy );
for( Rectangle2D rectangle : pendingRectangles ) {
fillRect( imageData, color, (int) Math.round( rectangle.getMinX() ),
(int) Math.round( rectangle.getMinY() ), (int) Math.round( rectangle.getWidth() ),
(int) Math.round( rectangle.getHeight() ) );
}
pendingRectangles.clear();
changed = true;
}
}
private void paintContent(final int cycle) {
synchronized( imageData ) {
if( changed ) {
GraphicsContext gc = canvas.getGraphicsContext2D();
PixelWriter pixelWriter = gc.getPixelWriter();
pixelWriter.setPixels( 0, 0, WIDTH, HEIGHT, pixelFormat, imageData, 0, WIDTH * 4 );
changed = false;
}
}
}
private void adjustAlpha(final byte[] imageData, final int decreaseBy) {
for( int i = 0; i < imageData.length; i += 4 ) {
imageData[i + 3] = (byte) Math.max( (imageData[i + 3] & 0xff) - decreaseBy, 0x0 );
}
}
private void fillRect(final byte[] imageData, final Color color, final int startX, final int startY,
final int width, final int height) {
for( int y = startY; y < startY + height; y++ ) {
for( int x = startX; x < startX + width; x++ ) {
int index = getStartIndex( y, x );
imageData[index] = blueByte;
imageData[index + 1] = greenByte;
imageData[index + 2] = redByte;
imageData[index + 3] = alphaByte;
}
}
}
private int getStartIndex(final int row, final int column) {
return row * WIDTH * 4 + column * 4;
}
}