JavaFX 内存使用:setFill() 与 -fx-fill
JavaFX memory usage: setFill() vs -fx-fill
我目前正在开发一个用 Java(FX) 编写的 2D 俯视游戏。每个新游戏世界都会根据 Perlin Noise 创建一个 运行dom 地图(背景和植被),创建的对象数量在 5000 - 7000 之间。植被的各个部分(树木,灌木,岩石,等)表示为用图像“填充”的矩形。
在玩游戏时,玩家可以退出当前世界并在 he/she 需要时创建一个新的 运行dom。这样做时,将创建 5000 - 7000 个都需要图像的新对象。
据我所知,在 JavaFX 中有两种方法可以将图像添加到矩形:
- 通过使用 rectangle.setFill(new ImagePattern(new Image(path)))
- 或者通过添加 CSS 样式类并使用 -fx-fill:url(路径)
使用第一个选项我很快 运行 进入 OutOfMemoryErrors,而第二个选项运行非常流畅。我决定启动 VisualVM 以查看内存使用量的实际差异有多大,这太疯狂了。请参阅下面 VisualVM 的屏幕截图以了解一个想法(正在创建 3 个新世界):
option1
option2
虽然这两个选项都将图像数据存储在内存的字节中[],但我想知道内存使用量的巨大差异从何而来? CSS 是否能够以某种方式“填充”矩形而不创建某种图像容器和图像本身?如果是这样,是否可以将其适应 JavaFXs setFill() 方法?我错过了什么?
您似乎在为每个矩形创建一个新的 Image
。如果您要创建 5000-7000 个矩形,那么您将拥有 5000-7000 个 Image
个实例,这些实例可能会复制大量相同的图像数据。
相反,只需缓存 Image
s,这样每个路径只加载一个:
private final Map<String, Image> imageCache = new HashMap<>();
然后
// rectangle.setFill(new ImagePattern(new Image(path));
rectangle.setFill(new ImagePattern(imageCache.computeIfAbsent(path, Image::new)));
如果您的“世界”使用不同的图像,它们之间不共享,您可以在加载新世界之前调用 imageCache.clear()
。根据您的用例,缓存 ImagePattern
而不是 Image
可能是有益的,尽管我猜测 ImagePattern
是它使用的图像的一个非常轻量级的包装器。
我目前正在开发一个用 Java(FX) 编写的 2D 俯视游戏。每个新游戏世界都会根据 Perlin Noise 创建一个 运行dom 地图(背景和植被),创建的对象数量在 5000 - 7000 之间。植被的各个部分(树木,灌木,岩石,等)表示为用图像“填充”的矩形。
在玩游戏时,玩家可以退出当前世界并在 he/she 需要时创建一个新的 运行dom。这样做时,将创建 5000 - 7000 个都需要图像的新对象。
据我所知,在 JavaFX 中有两种方法可以将图像添加到矩形:
- 通过使用 rectangle.setFill(new ImagePattern(new Image(path)))
- 或者通过添加 CSS 样式类并使用 -fx-fill:url(路径)
使用第一个选项我很快 运行 进入 OutOfMemoryErrors,而第二个选项运行非常流畅。我决定启动 VisualVM 以查看内存使用量的实际差异有多大,这太疯狂了。请参阅下面 VisualVM 的屏幕截图以了解一个想法(正在创建 3 个新世界):
option1
option2
虽然这两个选项都将图像数据存储在内存的字节中[],但我想知道内存使用量的巨大差异从何而来? CSS 是否能够以某种方式“填充”矩形而不创建某种图像容器和图像本身?如果是这样,是否可以将其适应 JavaFXs setFill() 方法?我错过了什么?
您似乎在为每个矩形创建一个新的 Image
。如果您要创建 5000-7000 个矩形,那么您将拥有 5000-7000 个 Image
个实例,这些实例可能会复制大量相同的图像数据。
相反,只需缓存 Image
s,这样每个路径只加载一个:
private final Map<String, Image> imageCache = new HashMap<>();
然后
// rectangle.setFill(new ImagePattern(new Image(path));
rectangle.setFill(new ImagePattern(imageCache.computeIfAbsent(path, Image::new)));
如果您的“世界”使用不同的图像,它们之间不共享,您可以在加载新世界之前调用 imageCache.clear()
。根据您的用例,缓存 ImagePattern
而不是 Image
可能是有益的,尽管我猜测 ImagePattern
是它使用的图像的一个非常轻量级的包装器。