/* * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package test.javafx.scene.shape.meshmanagercacheleaktest; import com.sun.javafx.tk.Toolkit; import javafx.application.Application; import javafx.application.Platform; import javafx.scene.Group; import javafx.scene.Scene; import javafx.stage.Stage; import javafx.stage.WindowEvent; import javafx.scene.layout.HBox; import javafx.scene.shape.Box; import javafx.scene.shape.Cylinder; import javafx.scene.shape.Shape3D; import javafx.scene.shape.Sphere; import java.util.concurrent.TimeUnit; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.CountDownLatch; import test.util.Util; import static test.javafx.scene.shape.meshmanagercacheleaktest.Constants.*; /* * Test application launched by MeshManagerCacheLeakTest with -Xmx16m. * Test steps: * 1. Create scene with a container. * 2. Reserve maximum memory of available memory. * 3. Add and remove different sized shapes to scene. * 4. Verify that, no OOM occurs. */ public class MeshManagerCacheLeakApp { // Socket for communicating with MeshManagerCacheLeakTest private static Socket socket; private static OutputStream out; private static boolean statusWritten = false; static String shapeType; static int numShapes = 0; static CountDownLatch startupLatch = new CountDownLatch(1); static Group container; static volatile Stage stage; public static class TestApp extends Application { @Override public void start(Stage pStage) { // 1. Create scene with a container. stage = pStage; HBox root = new HBox(); container = new Group(); root.getChildren().add(container); Scene scene = new Scene(root); stage.setScene(scene); stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e -> Platform.runLater(startupLatch::countDown)); stage.setAlwaysOnTop(true); stage.show(); } } private static void initSocket(String[] args) throws Exception { int port = Integer.parseInt(args[0]); socket = new Socket((String)null, port); out = socket.getOutputStream(); out.write(SOCKET_HANDSHAKE); out.flush(); } private synchronized static void writeStatus(int status) { if (!statusWritten) { statusWritten = true; try { out.write(status); out.flush(); } catch (IOException ex) { ex.printStackTrace(System.err); } } } public void testOOM() { AtomicInteger err = new AtomicInteger(STATUS_OOM); try { // 2. Reserve maximum memory of available memory. byte[] mem = null; if (shapeType.equals("Sphere")) { mem = new byte[((int)Runtime.getRuntime().freeMemory()) - 1024 * 512 * 3]; } else if (shapeType.equals("Box")) { mem = new byte[((int)Runtime.getRuntime().freeMemory()) - 1024 * 512 * 1]; } else if (shapeType.equals("Cylinder")) { mem = new byte[((int)Runtime.getRuntime().freeMemory()) - 1024 * 512 * 1]; } float radius = 20.0f; float height = 20; int divisions = 64; int boxWHD = 300; for (int i = 0 ; i < numShapes; ++i) { // 3. Add and remove different sized shapes to scene. Shape3D shape = null; if (shapeType.equals("Sphere")) { shape = new Sphere(radius++, divisions); } else if (shapeType.equals("Box")) { shape = new Box(boxWHD++, boxWHD, boxWHD); } else if (shapeType.equals("Cylinder")) { shape = new Cylinder(radius++, height); } Shape3D shp = shape; CountDownLatch latch = new CountDownLatch(1); Util.runAndWait(() -> { try { container.getChildren().add(shp); Toolkit.getToolkit().firePulse(); Thread.sleep(5000 / numShapes); container.getChildren().clear(); Toolkit.getToolkit().firePulse(); latch.countDown(); } catch (OutOfMemoryError e) { writeStatus(err.get()); System.exit(0); } catch (Exception e) { writeStatus(err.get()); System.exit(0); } waitForLatch(latch, 5); }); } } catch (OutOfMemoryError e) { writeStatus(err.get()); System.exit(0); } catch (Exception e) { writeStatus(err.get()); System.exit(0); } // 4. Verify that, no OOM occurs. err.set(STATUS_OK); writeStatus(err.get()); System.exit(ERROR_NONE); } public void waitForLatch(CountDownLatch latch, int seconds) { try { if (!latch.await(seconds, TimeUnit.SECONDS)) { System.exit(ERROR_LAUNCH); } } catch (Exception ex) { System.exit(ERROR_LAUNCH); } } public static void main(String[] args) { try { initSocket(args); } catch (Exception ex) { ex.printStackTrace(System.err); System.exit(ERROR_SOCKET); } shapeType = args[1]; numShapes = Integer.parseInt(args[2]); MeshManagerCacheLeakApp test = new MeshManagerCacheLeakApp(); new Thread(() -> Application.launch(TestApp.class, (String[])null)).start(); test.waitForLatch(startupLatch, 10); test.testOOM(); } }