多次使用 CesiumJS LookAt 方法时浏览器(Chrome 和 Firefox)内存不足

luk*_*kro 7 javascript out-of-memory cesiumjs

注意:这似乎是一个与系统相关的问题:它发生在 Windows 10 Home(版本 21H1)、图形 Nvidia GeForce GTX 980M 和浏览器 Firefox(91.0.2(64 位))和 Chrome(版本 93.0.4577.63)上( 64 位))。但在另一台配备 Ubuntu 20.04 LTS、Intel UHD Graphics 620 和 Chromium 版本 93.0.4577.63 的笔记本电脑上则不会出现此问题。

为什么多次调用CesiumJS的lookAt方法后内存不足?对于一个项目,我想一个接一个地查看许多不同的点,并为此调用循环这些点的 LookAt 函数。经过几次调用后,响应速度越来越慢,浏览器内存使用量不断增加,直到出现内存不足错误。我在 Firefox 和 Chrome 中本地运行了代码。两者在运行 30 到 300 次后都会遇到此错误,具体取决于相机距离,距离越远,需要加载的图块就越多,因此内存错误发生的速度就越快。但也在 sandcastle:https://sandcastle.cesium.com/中,我遇到了浏览器内存不断增加直至浏览器崩溃的问题。

我的电脑有 32GB 内存。在调用 LookAt 大约 30 次后,Firefox 消耗了 20GB 内存,然后我才能在开发者控制台上看到我们的内存错误。Chrome 在内存不足之前仅消耗 8 GB,但似乎处理调用的速度更快。

有谁知道,可能是怎么回事?我确实试图在每次观看后摧毁观众,但这根本没有帮助。预先非常感谢您的帮助!

您可以将以下代码按原样粘贴到 sandcastle 中。只需要更多坐标,因为为了更好的可读性,我删除了其中的大部分坐标。

/*I have added around 350 points here, but to improve readbility, I removed most of them 
  const points = [
  [49.311814789194564, 6.670985819810598],
  [48.311814789194564, 6.670985819810598],
[50.311814789194564, 6.670985819810598]
];*/

//random generation instead for testing purposes
const points = Array(350).fill().map((_, index, a) => ([42 + 20/a.length * index, 20/a.length * index]));


function awaitTileLoadingComplete(viewer){
  return new Promise((resolve) => {
    const listener = () => {
      if(viewer.scene.globe.tilesLoaded) {
        viewer.scene.globe.tileLoadProgressEvent.removeEventListener(listener);
        resolve();
      }
    };
    viewer.scene.globe.tileLoadProgressEvent.addEventListener(listener);
  });
}

async function getTerrainHeight(long, lat, viewer){
  const pointOfInterest = Cesium.Cartographic.fromDegrees(
    long, lat, 5000, new Cesium.Cartographic()
  );  
  return (await Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, [pointOfInterest]))[0].height;
}

async function lookAt(viewer, lat, lon, heading, pitch, range) {
  heading = Cesium.Math.toRadians(50.0);
  pitch = Cesium.Math.toRadians(pitch);
  viewer.camera.lookAt(
    Cesium.Cartesian3.fromDegrees(lon, lat, await getTerrainHeight(lon, lat, viewer) + 100),
    new Cesium.HeadingPitchRange(heading, pitch, range)
  );
}

async function lookAtPointAndWait(viewer, point) {
  await lookAt(viewer, point[0], point[1], 90, -3, 5000);
  await awaitTileLoadingComplete(viewer);
  // Wait a second for everything to actually be rendered:
  await new Promise(resolve => setTimeout(resolve, 1000));
}

async function main() {
  const viewer = new Cesium.Viewer("cesiumContainer", {
    terrainProvider: Cesium.createWorldTerrain(),
  });     
  viewer.scene.debugShowFramesPerSecond = true;
  viewer.scene.fog.enabled = false;
  viewer.scene.primitives.add(Cesium.createOsmBuildings());
  
  await points.reduce(
    (promise, point) => promise.then(() => lookAtPointAndWait(viewer, point)),
    Promise.resolve()
  );
}

main();
Run Code Online (Sandbox Code Playgroud)