2014-10-08 4 views
4

После нескольких часов на час, пытаясь выследить ошибка памяти в моем приложении, мне удалось свести его к какой-то самого странное поведение в простой программе JFX:Bizarre JavaFX8 OutOfMemoryError - FadeTransition

Возьмите следующие простой пример, который постепенно исчезает прямоугольник на прозрачном полотне:

public class Test extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     primaryStage.initStyle(StageStyle.TRANSPARENT); 
     int width = 1920; 
     int height = 1080; 

     Rectangle rect = new Rectangle(width, height); 
     rect.setFill(Color.SALMON); 
     rect.setOpacity(0); 
     StackPane scenePane = new StackPane(); 
     scenePane.getChildren().add(rect); 
     primaryStage.setScene(new Scene(scenePane)); 
     primaryStage.setWidth(width); 
     primaryStage.setHeight(height); 
     primaryStage.show(); 
     FadeTransition ft = new FadeTransition(Duration.millis(10000), rect); 
     ft.setToValue(1); 
     ft.play(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

} 

при запуске с арг VM -Xms100m -Xmx100m, это не работает никаких проблем. Однако, когда я даю ВМ по существу более памяти (например, -Xms1000m -Xmx1000m) очень быстро падает:

java.lang.OutOfMemoryError 
     at sun.misc.Unsafe.allocateMemory(Native Method) 
     at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:127) 
     at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) 
     at com.sun.prism.impl.BufferUtil.newByteBuffer(BufferUtil.java:90) 
     at com.sun.prism.impl.BufferUtil.newIntBuffer(BufferUtil.java:121) 
     at com.sun.javafx.tk.quantum.UploadingPainter.run(UploadingPainter.java:148) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) 
     at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) 
     at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
     at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125) 
     at java.lang.Thread.run(Thread.java:745) 

Более один профайлер я попытался показывает кучу в качестве занимая едва ли аллоцированных space - но представление процесса в диспетчере задач показывает, что он через всю оставшуюся память застревает всю доступную память.

Причуда не заканчивается, однако - это только кажется, падать при некоторых значениях width и heightwidth 1921, например, означает, что приложение выполняет отлично, без ошибок в поле зрения.)

Это похоже на прозрачную стадию. Без прозрачного стиля, установленного на сцене в первой строке, все выглядит хорошо (со всеми конфигурациями, которые я пробовал, во всяком случае.) Точно так же это происходит только на Java 8 (я использую 8u20) - все в порядке с Java 7/JFX 2.x. Я запускаю Windows 7x64.

Может ли кто-нибудь воспроизвести эту проблему, и может ли кто-нибудь пролить свет на то, что может произойти ?! Это, безусловно, самый причудливый вещи я столкнулся в долгое время ...

UPDATE: я сумел воспроизвести это на отдельном компьютере Windows 8, однако другой 7 ящик для Windows (и Mac) оба кажутся прекрасными. Не уверен, какой именно код JFX-кода я нажимаю, но, похоже, он, похоже, полностью зависит от машины.

+0

Устранена ли проблема, если вы вызываете 'ft.play();' в новый 'Thread'? –

+0

@ElliottFrisch Nope, просто попробовал это с тем же результатом. – berry120

ответ

5

Это только ответы часть вашего вопроса, но вот почему увеличить кучу приведет к OutOfMemeoryError:

Как вы можете видеть из StackTrace, JavaFX использует DirectByteBuffer для его обработки - поэтому данные не хранится в куче, но в родной память. Увеличивая размер вашей (фиксированной) кучи, вы уменьшаете объем свободной памяти, которую ваша ОС может предлагать как встроенную память.

E.g. на окнах с 32-разрядной Java-VM адресный диапазон памяти составляет 4 ГБ, 2 ГБ зарезервированы для ОС, оставляя 2 ГБ для java-приложения. С -Xms1000m -Xmx1000m другой ГБ зарезервирован для кучи, оставляя 1 ГБ для VM-кода, стека, Non-heap-memory (например, PermGen и т. Д.), И то, что осталось от его окончательного GB, можно использовать в качестве собственной памяти.

+0

+1 и хороший момент - я не принял это во внимание. Как вы говорите, я не думаю, что это полная проблема, так как я могу взять размер кучи до 900 м или до 1500 м и все еще есть проблема. (Я бы не ожидал, что использование собственной памяти для перехода к постепенному исчезновению приблизится к отметке 600 м.) – berry120

+0

Я также не думаю, что это один переход с использованием 600 м, но вы также должны наблюдать за потреблением памяти на OS- Уровень - например используя TaskManager. –

+0

У меня есть - он взлетает примерно до 1500 м, как только начинается переход, а затем заканчивается память. FWIW, я подал JIRA: https://javafx-jira.kenai.com/browse/RT-38923 - ребята из JFX, похоже, думают, что это потому, что GC недостаточно агрессивно освобождает родные кучи, поскольку они должны быть в очереди, что имеет смысл. – berry120