Changeset 8860 in josm for trunk/src/org


Ignore:
Timestamp:
2015-10-11T22:43:40+02:00 (4 years ago)
Author:
wiktorn
Message:

Make MemoryTileCache instiated per-layer instead static.

Static MemoryTIleCache put quite a lot of pressure on the cache, esp. when
working with multiple layers. Instead of growing MemoryTileCache, small
instances per layer are implemented.

As MemoryTileCache might also put a lot pressure on memory, now size of
MemoryTileCache is calculated based on screen resolution, assuming, that user
will work in full screen mode. Implementation also checks, if all added layers
will not require more memory that is allocated for JOSM, to prevent unexpected
OutOfMemoryException.

Location:
trunk/src/org/openstreetmap/josm/gui/layer
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java

    r8855 r8860  
    151151     *  in MapView (for example - when limiting min zoom in imagery)
    152152     *
    153      *  Use static instance so memory is shared between layers to prevent out of memory exceptions, when user is working with many layers
    154      */
    155     protected static TileCache tileCache = new MemoryTileCache(MEMORY_CACHE_SIZE.get());
     153     *  Use per-layer tileCache instance, as the more layers there are, the more tiles needs to be cached
     154     */
     155    protected TileCache tileCache; // initialized together with tileSource
    156156    protected AbstractTMSTileSource tileSource;
    157157    protected TileLoader tileLoader;
     
    166166        this.setVisible(true);
    167167        MapView.addZoomChangeListener(this);
     168        this.tileSource = getTileSource(info);
     169        if (this.tileSource == null) {
     170            throw new IllegalArgumentException(tr("Failed to create tile source"));
     171        }
    168172    }
    169173
     
    207211        if (tileLoader == null)
    208212            tileLoader = new OsmTileLoader(this, headers);
     213
     214        tileCache = new MemoryTileCache(estimateTileCacheSize());
    209215    }
    210216
     
    506512    @Override
    507513    public void hookUpMapView() {
    508         this.tileSource = getTileSource(info);
    509         if (this.tileSource == null) {
    510             throw new IllegalArgumentException(tr("Failed to create tile source"));
    511         }
    512 
     514        super.hookUpMapView();
    513515        projectionChanged(null, Main.getProjection()); // check if projection is supported
    514516        initTileSource(this.tileSource);
     
    660662    }
    661663
     664    @Override
     665    protected long estimateMemoryUsage() {
     666        return 4L * tileSource.getTileSize() * tileSource.getTileSize() * estimateTileCacheSize();
     667    }
     668
     669    protected int estimateTileCacheSize() {
     670        int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
     671        int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
     672        int tileSize = 256; // default tile size
     673        if (tileSource != null) {
     674            tileSize = tileSource.getTileSize();
     675        }
     676        // as we can see part of the tile at the top and at the bottom, use Math.ceil(...) + 1 to accommodate for that
     677        int visibileTiles = (int) (Math.ceil( (double)height / tileSize + 1) * Math.ceil((double)width / tileSize + 1));
     678        // add 10% for tiles from different zoom levels
     679        return (int)Math.ceil(
     680                Math.pow(2d, ZOOM_OFFSET.get()) * visibileTiles // use offset to decide, how many tiles are visible
     681                * 2);
     682    }
    662683    /**
    663684     * Checks zoom level against settings
     
    15101531            myDrawString(g, tr("Pixel scale: {0}", getScaleFactor(currentZoomLevel)), 50, 170);
    15111532            myDrawString(g, tr("Best zoom: {0}", getBestZoom()), 50, 185);
     1533            myDrawString(g, tr("Estimated cache size: {0}", estimateTileCacheSize()), 50, 200);
    15121534            if (tileLoader instanceof TMSCachedTileLoader) {
    15131535                TMSCachedTileLoader cachedTileLoader = (TMSCachedTileLoader) tileLoader;
    1514                 int offset = 185;
     1536                int offset = 200;
    15151537                for (String part: cachedTileLoader.getStats().split("\n")) {
    15161538                    myDrawString(g, tr("Cache stats: {0}", part), 50, offset += 15);
  • trunk/src/org/openstreetmap/josm/gui/layer/Layer.java

    r8855 r8860  
    138138     * not execute code in the constructor, that assumes Main.map.mapView is
    139139     * not null. Instead override this method.
     140     *
     141     * This implementation provides check, if JOSM will be able to use Layer. Layers
     142     * using a lot of memory, which do know in advance, how much memory they use, should
     143     * override {@link #estimateMemoryUsage() estimateMemoryUsage} method and give a hint.
     144     *
     145     * This allows for preemptive warning message for user, instead of failing later on
     146     *
     147     * Remember to call {@code super.hookUpMapView()} when overriding this method
    140148     */
    141149    public void hookUpMapView() {
     150        // calculate total memory needed for all layers
     151        long memoryBytesRequired = 50 * 1024 * 1024; // assumed minimum JOSM memory footprint
     152        if (Main.map != null && Main.map.mapView != null) {
     153            for (Layer layer: Main.map.mapView.getAllLayers()) {
     154                memoryBytesRequired += layer.estimateMemoryUsage();
     155            }
     156            if (memoryBytesRequired >  Runtime.getRuntime().maxMemory()) {
     157                throw new IllegalArgumentException(tr("To add another layer you need to allocate at least {0,number,#}MB memory to JOSM using -Xmx{0,number,#}M "
     158                        + "option (see http://forum.openstreetmap.org/viewtopic.php?id=25677).\n"
     159                        + "Currently you have {1,number,#}MB memory allocated for JOSM", memoryBytesRequired / 1024 / 1024, Runtime.getRuntime().maxMemory() / 1024 / 1024));
     160            }
     161        }
    142162    }
    143163
     
    507527        return SaveActionBase.createAndOpenSaveFileChooser(tr("Save Layer"), "lay");
    508528    }
     529
     530    /**
     531     * @return bytes that the tile will use. Needed for resource management
     532     */
     533    protected long estimateMemoryUsage() {
     534        return 0;
     535    }
    509536}
Note: See TracChangeset for help on using the changeset viewer.