static class VMRuntimeHack {
private Object runtime = null;
private Method trackAllocation = null;
private Method trackFree = null;
public boolean trackAlloc(long size) {
if (runtime == null)
return false;
try {
Object res = trackAllocation.invoke(runtime, Long.valueOf(size));
return (res instanceof Boolean) ? (Boolean)res : true;
} catch (IllegalArgumentException e) {
return false;
} catch (IllegalAccessException e) {
return false;
} catch (InvocationTargetException e) {
return false;
}
}
public boolean trackFree(long size) {
if (runtime == null)
return false;
try {
Object res = trackFree.invoke(runtime, Long.valueOf(size));
return (res instanceof Boolean) ? (Boolean)res : true;
} catch (IllegalArgumentException e) {
return false;
} catch (IllegalAccessException e) {
return false;
} catch (InvocationTargetException e) {
return false;
}
}
public VMRuntimeHack() {
boolean success = false;
try {
Class cl = Class.forName("dalvik.system.VMRuntime");
Method getRt = cl.getMethod("getRuntime", new Class[0]);
runtime = getRt.invoke(null, new Object[0]);
trackAllocation = cl.getMethod("trackExternalAllocation", new Class[] {long.class});
trackFree = cl.getMethod("trackExternalFree", new Class[] {long.class});
success = true;
} catch (ClassNotFoundException e) {
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
if (!success) {
Log.i(TAG, "VMRuntime hack does not work!");
runtime = null;
trackAllocation = null;
trackFree = null;
}
}
}
private static final VMRuntimeHack runtime = new VMRuntimeHack();
static class BitmapFactory {
public BitmapFactory(boolean useHack) {
this.useHack = useHack;
}
// создать картинку
public Bitmap alloc(int dx, int dy) {
Bitmap bmp = Bitmap.createBitmap(dx, dy, Bitmap.Config.RGB_565);
if (useHack) {
runtime.trackFree(bmp.getRowBytes() * bmp.getHeight());
hackedBitmaps.add(bmp);
}
allocatedBitmaps.add(bmp);
return bmp;
}
// освободить картинку
public void free(Bitmap bmp) {
bmp.recycle();
if (hackedBitmaps.contains(bmp)) {
runtime.trackAlloc(bmp.getRowBytes() * bmp.getHeight());
hackedBitmaps.remove(bmp);
}
allocatedBitmaps.remove(bmp);
}
// освоболить все картинки (удобно для тестирования)
public void freeAll() {
for (Bitmap bmp : new LinkedList<Bitmap>(allocatedBitmaps))
free(bmp);
}
private final boolean useHack;
private Set<Bitmap> allocatedBitmaps = new HashSet<Bitmap>();
private Set<Bitmap> hackedBitmaps = new HashSet<Bitmap>();
}
public int testAllocation(boolean useHack, int maxAlloc) {
System.gc();
BitmapFactory factory = new BitmapFactory(useHack);
int allocated = 0;
// AndroidRuntime: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
while (allocated < maxAlloc) {
try {
Bitmap bmp = factory.alloc(1024, 512);
allocated += bmp.getRowBytes() * bmp.getHeight();
Log.i(TAG, "Bitmap bytes allocated " + allocated);
} catch (OutOfMemoryError e) {
Log.e(TAG, "Exception while allocation of bitmap, total size = " + allocated, e);
break;
}
}
factory.freeAll();
return allocated;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// perform test
int allocatedNormally = testAllocation(false, 48 * MB);
int allocatedWithHack = testAllocation(true, 48 * MB);
String msg = "normally: " + (allocatedNormally / MB) + " MB allocated " +
"\nwith hack: " + (allocatedWithHack / MB) + " MB allocated";
Log.i(TAG, msg);
// display results
LayoutInflater inflater = LayoutInflater.from(this);
View main = (View)inflater.inflate(R.layout.main, null);
TextView text = (TextView)main.findViewById(R.id.text);
text.setText(msg);
setContentView(main);
}
03-07 09:43:37.233: I/bmphack(17873): normally: 10 MB allocated
03-07 09:43:37.233: I/bmphack(17873): with hack: 48 MB allocated
Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.
комментарии (26)