From 65b345fa22b878e141b8fd8ece9c208df00fa40f Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Wed, 27 Jul 2011 18:51:50 -0700 Subject: Reclaim more memory, more often. Yay. Change-Id: I04557ad575c307a55088549f48f0e9ad994b7275 --- core/java/android/view/DisplayList.java | 7 ++++ core/java/android/view/GLES20Canvas.java | 6 +++ core/java/android/view/GLES20DisplayList.java | 6 +++ core/java/android/view/HardwareRenderer.java | 4 +- core/java/android/view/View.java | 6 ++- core/java/android/view/ViewDebug.java | 2 +- core/java/android/view/ViewRootImpl.java | 53 ++++++++++++++++++++---- core/java/android/view/WindowManagerImpl.java | 58 ++++++++++++++++++++++++++- 8 files changed, 130 insertions(+), 12 deletions(-) (limited to 'core/java/android/view') diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index f4c0249..8f4ece0 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -54,4 +54,11 @@ public abstract class DisplayList { * @return boolean true if the display list is able to be replayed, false otherwise. */ abstract boolean isValid(); + + /** + * Return the amount of memory used by this display list. + * + * @return The size of this display list in bytes + */ + abstract int getSize(); } diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index ac0abc3..a7fe95d 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -330,6 +330,12 @@ class GLES20Canvas extends HardwareCanvas { private static native void nDestroyDisplayList(int displayList); + static int getDisplayListSize(int displayList) { + return nGetDisplayListSize(displayList); + } + + private static native int nGetDisplayListSize(int displayList); + @Override public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) { return nDrawDisplayList(mRenderer, diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java index 9e649ce..4ca5e98 100644 --- a/core/java/android/view/GLES20DisplayList.java +++ b/core/java/android/view/GLES20DisplayList.java @@ -82,6 +82,12 @@ class GLES20DisplayList extends DisplayList { } } + @Override + int getSize() { + if (mFinalizer == null) return 0; + return GLES20Canvas.getDisplayListSize(mFinalizer.mNativeDisplayList); + } + private static class DisplayListFinalizer { final int mNativeDisplayList; diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 5404e3a..4e4923b 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -934,7 +934,9 @@ public abstract class HardwareRenderer { } private void destroyHardwareLayer(View view) { - view.destroyLayer(); + if (view.destroyLayer()) { + view.invalidate(true); + } if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 5b8a201..bfa525c 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2294,8 +2294,8 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit private Bitmap mDrawingCache; private Bitmap mUnscaledDrawingCache; - private DisplayList mDisplayList; private HardwareLayer mHardwareLayer; + DisplayList mDisplayList; /** * When this view has focus and the next focus is {@link #FOCUS_LEFT}, @@ -9727,11 +9727,13 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit return mHardwareLayer; } - void destroyLayer() { + boolean destroyLayer() { if (mHardwareLayer != null) { mHardwareLayer.destroy(); mHardwareLayer = null; + return true; } + return false; } /** diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 4acf48c..96e550e 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -420,7 +420,7 @@ public class ViewDebug { * * @hide */ - public static long getViewAncestorInstanceCount() { + public static long getViewRootImplCount() { return Debug.countInstancesOfClass(ViewRootImpl.class); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 57bf17f..cddf41e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -80,6 +80,7 @@ import com.android.internal.view.RootViewSurfaceTaker; import java.io.IOException; import java.io.OutputStream; +import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -235,7 +236,6 @@ public final class ViewRootImpl extends Handler implements ViewParent, final Configuration mLastConfiguration = new Configuration(); final Configuration mPendingConfiguration = new Configuration(); - class ResizedInfo { Rect coveredInsets; Rect visibleInsets; @@ -542,10 +542,26 @@ public final class ViewRootImpl extends Handler implements ViewParent, } private void destroyHardwareResources() { - if (mAttachInfo.mHardwareRenderer.isEnabled()) { - mAttachInfo.mHardwareRenderer.destroyLayers(mView); + if (mAttachInfo.mHardwareRenderer != null) { + if (mAttachInfo.mHardwareRenderer.isEnabled()) { + mAttachInfo.mHardwareRenderer.destroyLayers(mView); + } + mAttachInfo.mHardwareRenderer.destroy(false); + } + } + + void destroyHardwareLayers() { + if (mThread != Thread.currentThread()) { + if (mAttachInfo.mHardwareRenderer != null && + mAttachInfo.mHardwareRenderer.isEnabled()) { + HardwareRenderer.trimMemory(ComponentCallbacks.TRIM_MEMORY_MODERATE); + } + } else { + if (mAttachInfo.mHardwareRenderer != null && + mAttachInfo.mHardwareRenderer.isEnabled()) { + mAttachInfo.mHardwareRenderer.destroyLayers(mView); + } } - mAttachInfo.mHardwareRenderer.destroy(false); } private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { @@ -876,9 +892,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, attachInfo.mWindowVisibility = viewVisibility; host.dispatchWindowVisibilityChanged(viewVisibility); if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { - if (mAttachInfo.mHardwareRenderer != null) { - destroyHardwareResources(); - } + destroyHardwareResources(); } if (viewVisibility == View.GONE) { // After making a window gone, we will count it as being @@ -3492,6 +3506,31 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void debug() { mView.debug(); } + + public void dumpGfxInfo(PrintWriter pw, int[] info) { + if (mView != null) { + getGfxInfo(mView, info); + } else { + info[0] = info[1] = 0; + } + } + + private void getGfxInfo(View view, int[] info) { + DisplayList displayList = view.mDisplayList; + info[0]++; + if (displayList != null) { + info[1] += displayList.getSize(); + } + + if (view instanceof ViewGroup) { + ViewGroup group = (ViewGroup) view; + + int count = group.getChildCount(); + for (int i = 0; i < count; i++) { + getGfxInfo(group.getChildAt(i), info); + } + } + } public void die(boolean immediate) { if (immediate) { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index a451bb5..5ef4f3e 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -24,6 +24,9 @@ import android.util.AndroidRuntimeException; import android.util.Log; import android.view.inputmethod.InputMethodManager; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.PrintWriter; import java.util.HashMap; final class WindowLeaked extends AndroidRuntimeException { @@ -392,7 +395,7 @@ public class WindowManagerImpl implements WindowManager { leak.setStackTrace(root.getLocation().getStackTrace()); Log.e("WindowManager", leak.getMessage(), leak); } - + removeViewLocked(i); i--; count--; @@ -410,6 +413,59 @@ public class WindowManagerImpl implements WindowManager { } } + /** + * @hide + */ + public void trimLocalMemory() { + synchronized (this) { + if (mViews == null) return; + int count = mViews.length; + for (int i = 0; i < count; i++) { + mRoots[i].destroyHardwareLayers(); + } + } + } + + /** + * @hide + */ + public void dumpGfxInfo(FileDescriptor fd) { + FileOutputStream fout = new FileOutputStream(fd); + PrintWriter pw = new PrintWriter(fout); + try { + synchronized (this) { + if (mViews != null) { + pw.println("View hierarchy:"); + + final int count = mViews.length; + + int viewsCount = 0; + int displayListsSize = 0; + int[] info = new int[2]; + + for (int i = 0; i < count; i++) { + ViewRootImpl root = mRoots[i]; + root.dumpGfxInfo(pw, info); + + String name = root.getClass().getName() + '@' + + Integer.toHexString(hashCode()); + pw.printf(" %s: %d views, %.2f kB (display lists)\n", + name, info[0], info[1] / 1024.0f); + + viewsCount += info[0]; + displayListsSize += info[1]; + } + + pw.printf("\nTotal ViewRootImpl: %d\n", count); + pw.printf("Total Views: %d\n", viewsCount); + pw.printf("Total DisplayList: %.2f kB\n\n", displayListsSize / 1024.0f); + } + } + } finally { + pw.flush(); + } + } + public void setStoppedState(IBinder token, boolean stopped) { synchronized (this) { if (mViews == null) -- cgit v1.1