aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-05-24 21:14:31 -0700
committerTor Norbye <tnorbye@google.com>2012-05-24 21:14:31 -0700
commit17ab2d456130393ee1fbcec03694627ba7cc72e5 (patch)
tree77497cc45c0dde800a36f0f38ec2739271ad23ed
parent631b384f32459fd99b29d9843ea2dbd2b8e533c9 (diff)
downloadsdk-17ab2d456130393ee1fbcec03694627ba7cc72e5.zip
sdk-17ab2d456130393ee1fbcec03694627ba7cc72e5.tar.gz
sdk-17ab2d456130393ee1fbcec03694627ba7cc72e5.tar.bz2
Use soft references for the AWT image cache
The layout editor stores both an SWT image (of the most recently rendered scene), as well as an AWT image which is kept around such that it can be used over again and over again as the scratch buffer for layout lib. However, if you're opening a lot of editors, there's a lot of these AWT buffers sitting around and most of the time not getting used. In a low memory situation they should be able to be freed up. To allow for this, the AWT image buffers are now held only by a soft (not weak) reference. If the soft reference is cleared by the garbage collector, then a new AWT image buffer will be allocated when needed for layoutlib. There is one wrinkle in all this: On Linux, we prescale images (because scaling while painting is very slow -- see issue 19447). This means we need to keep the AWT image around. Thus, there's a second field which is strong reference to the AWT image, which we set if prescaling is enabled. Change-Id: Ifb64e476c29194f0e99fec023612f9dc880dd6f4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java56
1 files changed, 41 insertions, 15 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java
index a5df4bd..c402b2b 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java
@@ -32,6 +32,7 @@ import org.eclipse.swt.graphics.PaletteData;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.WritableRaster;
+import java.lang.ref.SoftReference;
/**
* The {@link ImageOverlay} class renders an image as an overlay.
@@ -56,7 +57,17 @@ public class ImageOverlay extends Overlay implements IImageFactory {
/** Current background AWT image. This is created by {@link #getImage()}, which is called
* by the LayoutLib. */
- private BufferedImage mAwtImage;
+ private SoftReference<BufferedImage> mAwtImage = new SoftReference<BufferedImage>(null);
+
+ /**
+ * Strong reference to the image in the above soft reference, to prevent
+ * garbage collection when {@link PRESCALE} is set, until the scaled image
+ * is created (lazily as part of the next paint call, where this strong
+ * reference is nulled out and the above soft reference becomes eligible to
+ * be reclaimed when memory is low.)
+ */
+ @SuppressWarnings("unused") // Used by the garbage collector to keep mAwtImage non-soft
+ private BufferedImage mAwtImageStrongRef;
/** The associated {@link LayoutCanvas}. */
private LayoutCanvas mCanvas;
@@ -109,8 +120,10 @@ public class ImageOverlay extends Overlay implements IImageFactory {
* @return The corresponding SWT image, or null.
*/
public synchronized Image setImage(BufferedImage awtImage, boolean isAlphaChannelImage) {
- if (awtImage != mAwtImage || awtImage == null) {
- mAwtImage = null;
+ BufferedImage oldAwtImage = mAwtImage.get();
+ if (awtImage != oldAwtImage || awtImage == null) {
+ mAwtImage.clear();
+ mAwtImageStrongRef = null;
if (mImage != null) {
mImage.dispose();
@@ -165,7 +178,12 @@ public class ImageOverlay extends Overlay implements IImageFactory {
*/
@Nullable
BufferedImage getAwtImage() {
- return mAwtImage;
+ BufferedImage awtImage = mAwtImage.get();
+ if (awtImage == null && mImage != null) {
+ awtImage = SwtUtils.convertToAwt(mImage);
+ }
+
+ return awtImage;
}
@Override
@@ -184,11 +202,12 @@ public class ImageOverlay extends Overlay implements IImageFactory {
// This is done lazily in paint rather than when the image changes because
// the image must be rescaled each time the zoom level changes, which varies
// independently from when the image changes.
- if (PRESCALE && mAwtImage != null) {
+ BufferedImage awtImage = mAwtImage.get();
+ if (PRESCALE && awtImage != null) {
if (mPreScaledImage == null ||
mPreScaledImage.getImageData().width != hi.getScalledImgSize()) {
- double xScale = hi.getScalledImgSize() / (double) mAwtImage.getWidth();
- double yScale = vi.getScalledImgSize() / (double) mAwtImage.getHeight();
+ double xScale = hi.getScalledImgSize() / (double) awtImage.getWidth();
+ double yScale = vi.getScalledImgSize() / (double) awtImage.getHeight();
BufferedImage scaledAwtImage;
// NOTE: == comparison on floating point numbers is okay
@@ -198,9 +217,9 @@ public class ImageOverlay extends Overlay implements IImageFactory {
// of rounding errors.
if (xScale == 1.0 && yScale == 1.0) {
// Scaling to 100% is easy!
- scaledAwtImage = mAwtImage;
+ scaledAwtImage = awtImage;
} else {
- scaledAwtImage = ImageUtils.scale(mAwtImage, xScale, yScale);
+ scaledAwtImage = ImageUtils.scale(awtImage, xScale, yScale);
}
assert scaledAwtImage.getWidth() == hi.getScalledImgSize();
if (mPreScaledImage != null && !mPreScaledImage.isDisposed()) {
@@ -208,6 +227,8 @@ public class ImageOverlay extends Overlay implements IImageFactory {
}
mPreScaledImage = SwtUtils.convertToSwt(mCanvas.getDisplay(), scaledAwtImage,
true /*transferAlpha*/, -1);
+ // We can't just clear the mAwtImageStrongRef here, because if the
+ // zooming factor changes, we may need to use it again
}
if (mPreScaledImage != null) {
@@ -349,14 +370,19 @@ public class ImageOverlay extends Overlay implements IImageFactory {
*/
@Override
public BufferedImage getImage(int w, int h) {
- if (mAwtImage == null ||
- mAwtImage.getWidth() != w ||
- mAwtImage.getHeight() != h) {
-
- mAwtImage = SwtReadyBufferedImage.createImage(w, h, getDevice());
+ BufferedImage awtImage = mAwtImage.get();
+ if (awtImage == null ||
+ awtImage.getWidth() != w ||
+ awtImage.getHeight() != h) {
+ mAwtImage.clear();
+ awtImage = SwtReadyBufferedImage.createImage(w, h, getDevice());
+ mAwtImage = new SoftReference<BufferedImage>(awtImage);
+ if (PRESCALE) {
+ mAwtImageStrongRef = awtImage;
+ }
}
- return mAwtImage;
+ return awtImage;
}
/**