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 中有两种方法可以将图像添加到矩形:

  1. 通过使用 rectangle.setFill(new ImagePattern(new Image(path)))
  2. 或者通过添加 CSS 样式类并使用 -fx-fill:url(路径)

使用第一个选项我很快 运行 进入 OutOfMemoryErrors,而第二个选项运行非常流畅。我决定启动 VisualVM 以查看内存使用量的实际差异有多大,这太疯狂了。请参阅下面 VisualVM 的屏幕截图以了解一个想法(正在创建 3 个新世界):

option1

option2

虽然这两个选项都将图像数据存储在内存的字节中[],但我想知道内存使用量的巨大差异从何而来? CSS 是否能够以某种方式“填充”矩形而不创建某种图像容器和图像本身?如果是这样,是否可以将其适应 JavaFXs setFill() 方法?我错过了什么?

您似乎在为每个矩形创建一个新的 Image。如果您要创建 5000-7000 个矩形,那么您将拥有 5000-7000 个 Image 个实例,这些实例可能会复制大量相同的图像数据。

相反,只需缓存 Images,这样每个路径只加载一个:

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 是它使用的图像的一个非常轻量级的包装器。