Merge "Remove CoreTests: HeapTest"
This commit is contained in:
@@ -1,476 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.core;
|
||||
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
import android.test.suitebuilder.annotation.MediumTest;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Log;
|
||||
import android.test.suitebuilder.annotation.Suppress;
|
||||
import dalvik.system.VMRuntime;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
public class HeapTest extends TestCase {
|
||||
|
||||
private static final String TAG = "HeapTest";
|
||||
|
||||
/**
|
||||
* Returns a WeakReference to an object that has no
|
||||
* other references. This is done in a separate method
|
||||
* to ensure that the Object's address isn't sitting in
|
||||
* a stale local register.
|
||||
*/
|
||||
private WeakReference<Object> newRef() {
|
||||
return new WeakReference<Object>(new Object());
|
||||
}
|
||||
|
||||
private static void makeRefs(Object objects[], SoftReference<Object> refs[]) {
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
objects[i] = (Object) new byte[8 * 1024];
|
||||
refs[i] = new SoftReference<Object>(objects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> int checkRefs(SoftReference<T> refs[], int last) {
|
||||
int i;
|
||||
int numCleared = 0;
|
||||
for (i = 0; i < refs.length; i++) {
|
||||
Object o = refs[i].get();
|
||||
if (o == null) {
|
||||
numCleared++;
|
||||
}
|
||||
}
|
||||
if (numCleared != last) {
|
||||
Log.i(TAG, "****** " + numCleared + "/" + i + " cleared ******");
|
||||
}
|
||||
return numCleared;
|
||||
}
|
||||
|
||||
private static void clearRefs(Object objects[], int skip) {
|
||||
for (int i = 0; i < objects.length; i += skip) {
|
||||
objects[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void clearRefs(Object objects[]) {
|
||||
clearRefs(objects, 1);
|
||||
}
|
||||
|
||||
private static <T> void checkRefs(T objects[], SoftReference<T> refs[]) {
|
||||
boolean ok = true;
|
||||
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (refs[i].get() != objects[i]) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
throw new RuntimeException("Test failed: soft refs not cleared");
|
||||
}
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testGcSoftRefs() throws Exception {
|
||||
final int NUM_REFS = 128;
|
||||
|
||||
Object objects[] = new Object[NUM_REFS];
|
||||
SoftReference<Object> refs[] = new SoftReference[objects.length];
|
||||
|
||||
/* Create a bunch of objects and a parallel array
|
||||
* of SoftReferences.
|
||||
*/
|
||||
makeRefs(objects, refs);
|
||||
Runtime.getRuntime().gc();
|
||||
|
||||
/* Let go of some of the hard references to the objects so that
|
||||
* the references can be cleared.
|
||||
*/
|
||||
clearRefs(objects, 3);
|
||||
|
||||
/* Collect all softly-reachable objects.
|
||||
*/
|
||||
VMRuntime.getRuntime().gcSoftReferences();
|
||||
Runtime.getRuntime().runFinalization();
|
||||
|
||||
/* Make sure that the objects were collected.
|
||||
*/
|
||||
checkRefs(objects, refs);
|
||||
|
||||
/* Remove more hard references and re-check.
|
||||
*/
|
||||
clearRefs(objects, 2);
|
||||
VMRuntime.getRuntime().gcSoftReferences();
|
||||
Runtime.getRuntime().runFinalization();
|
||||
checkRefs(objects, refs);
|
||||
|
||||
/* Remove the rest of the references and re-check.
|
||||
*/
|
||||
/* Remove more hard references and re-check.
|
||||
*/
|
||||
clearRefs(objects);
|
||||
VMRuntime.getRuntime().gcSoftReferences();
|
||||
Runtime.getRuntime().runFinalization();
|
||||
checkRefs(objects, refs);
|
||||
}
|
||||
|
||||
public void xxtestSoftRefPartialClean() throws Exception {
|
||||
final int NUM_REFS = 128;
|
||||
|
||||
Object objects[] = new Object[NUM_REFS];
|
||||
SoftReference<Object> refs[] = new SoftReference[objects.length];
|
||||
|
||||
/* Create a bunch of objects and a parallel array
|
||||
* of SoftReferences.
|
||||
*/
|
||||
makeRefs(objects, refs);
|
||||
Runtime.getRuntime().gc();
|
||||
|
||||
/* Let go of the hard references to the objects so that
|
||||
* the references can be cleared.
|
||||
*/
|
||||
clearRefs(objects);
|
||||
|
||||
/* Start creating a bunch of temporary and permanent objects
|
||||
* to drive GC.
|
||||
*/
|
||||
final int NUM_OBJECTS = 64 * 1024;
|
||||
Object junk[] = new Object[NUM_OBJECTS];
|
||||
Random random = new Random();
|
||||
|
||||
int i = 0;
|
||||
int mod = 0;
|
||||
int totalSize = 0;
|
||||
int cleared = -1;
|
||||
while (i < junk.length && totalSize < 8 * 1024 * 1024) {
|
||||
int r = random.nextInt(64 * 1024) + 128;
|
||||
Object o = (Object) new byte[r];
|
||||
if (++mod % 16 == 0) {
|
||||
junk[i++] = o;
|
||||
totalSize += r * 4;
|
||||
}
|
||||
cleared = checkRefs(refs, cleared);
|
||||
}
|
||||
}
|
||||
|
||||
private static void makeRefs(Object objects[], WeakReference<Object> refs[]) {
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
objects[i] = new Object();
|
||||
refs[i] = new WeakReference<Object>(objects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void checkRefs(T objects[], WeakReference<T> refs[]) {
|
||||
boolean ok = true;
|
||||
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (refs[i].get() != objects[i]) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
throw new RuntimeException("Test failed: " +
|
||||
"weak refs not cleared");
|
||||
}
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testWeakRefs() throws Exception {
|
||||
final int NUM_REFS = 16;
|
||||
|
||||
Object objects[] = new Object[NUM_REFS];
|
||||
WeakReference<Object> refs[] = new WeakReference[objects.length];
|
||||
|
||||
/* Create a bunch of objects and a parallel array
|
||||
* of WeakReferences.
|
||||
*/
|
||||
makeRefs(objects, refs);
|
||||
Runtime.getRuntime().gc();
|
||||
checkRefs(objects, refs);
|
||||
|
||||
/* Clear out every other strong reference.
|
||||
*/
|
||||
for (int i = 0; i < objects.length; i += 2) {
|
||||
objects[i] = null;
|
||||
}
|
||||
Runtime.getRuntime().gc();
|
||||
checkRefs(objects, refs);
|
||||
|
||||
/* Clear out the rest of them.
|
||||
*/
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
objects[i] = null;
|
||||
}
|
||||
Runtime.getRuntime().gc();
|
||||
checkRefs(objects, refs);
|
||||
}
|
||||
|
||||
private static void makeRefs(Object objects[], PhantomReference<Object> refs[],
|
||||
ReferenceQueue<Object> queue) {
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
objects[i] = new Object();
|
||||
refs[i] = new PhantomReference<Object>(objects[i], queue);
|
||||
}
|
||||
}
|
||||
|
||||
static <T> void checkRefs(T objects[], PhantomReference<T> refs[],
|
||||
ReferenceQueue<T> queue) {
|
||||
boolean ok = true;
|
||||
|
||||
/* Make sure that the reference that should be on
|
||||
* the queue are marked as enqueued. Once we
|
||||
* pull them off the queue, they will no longer
|
||||
* be marked as enqueued.
|
||||
*/
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (objects[i] == null && refs[i] != null) {
|
||||
if (!refs[i].isEnqueued()) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
throw new RuntimeException("Test failed: " +
|
||||
"phantom refs not marked as enqueued");
|
||||
}
|
||||
|
||||
/* Make sure that all of the references on the queue
|
||||
* are supposed to be there.
|
||||
*/
|
||||
PhantomReference<T> ref;
|
||||
while ((ref = (PhantomReference<T>) queue.poll()) != null) {
|
||||
/* Find the list index that corresponds to this reference.
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < objects.length; i++) {
|
||||
if (refs[i] == ref) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == objects.length) {
|
||||
throw new RuntimeException("Test failed: " +
|
||||
"unexpected ref on queue");
|
||||
}
|
||||
if (objects[i] != null) {
|
||||
throw new RuntimeException("Test failed: " +
|
||||
"reference enqueued for strongly-reachable " +
|
||||
"object");
|
||||
}
|
||||
refs[i] = null;
|
||||
|
||||
/* TODO: clear doesn't do much, since we're losing the
|
||||
* strong ref to the ref object anyway. move the ref
|
||||
* into another list.
|
||||
*/
|
||||
ref.clear();
|
||||
}
|
||||
|
||||
/* We've visited all of the enqueued references.
|
||||
* Make sure that there aren't any other references
|
||||
* that should have been enqueued.
|
||||
*
|
||||
* NOTE: there is a race condition here; this assumes
|
||||
* that the VM has serviced all outstanding reference
|
||||
* enqueue() calls.
|
||||
*/
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (objects[i] == null && refs[i] != null) {
|
||||
// System.out.println("HeapTest/PhantomRefs: refs[" + i +
|
||||
// "] should be enqueued");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
throw new RuntimeException("Test failed: " +
|
||||
"phantom refs not enqueued");
|
||||
}
|
||||
}
|
||||
|
||||
@MediumTest
|
||||
public void testPhantomRefs() throws Exception {
|
||||
final int NUM_REFS = 16;
|
||||
|
||||
Object objects[] = new Object[NUM_REFS];
|
||||
PhantomReference<Object> refs[] = new PhantomReference[objects.length];
|
||||
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
|
||||
|
||||
/* Create a bunch of objects and a parallel array
|
||||
* of PhantomReferences.
|
||||
*/
|
||||
makeRefs(objects, refs, queue);
|
||||
Runtime.getRuntime().gc();
|
||||
checkRefs(objects, refs, queue);
|
||||
|
||||
/* Clear out every other strong reference.
|
||||
*/
|
||||
for (int i = 0; i < objects.length; i += 2) {
|
||||
objects[i] = null;
|
||||
}
|
||||
// System.out.println("HeapTest/PhantomRefs: cleared evens");
|
||||
Runtime.getRuntime().gc();
|
||||
Runtime.getRuntime().runFinalization();
|
||||
checkRefs(objects, refs, queue);
|
||||
|
||||
/* Clear out the rest of them.
|
||||
*/
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
objects[i] = null;
|
||||
}
|
||||
// System.out.println("HeapTest/PhantomRefs: cleared all");
|
||||
Runtime.getRuntime().gc();
|
||||
Runtime.getRuntime().runFinalization();
|
||||
checkRefs(objects, refs, queue);
|
||||
}
|
||||
|
||||
private static int sNumFinalized = 0;
|
||||
private static final Object sLock = new Object();
|
||||
|
||||
private static class FinalizableObject {
|
||||
protected void finalize() {
|
||||
// System.out.println("gc from finalize()");
|
||||
Runtime.getRuntime().gc();
|
||||
synchronized (sLock) {
|
||||
sNumFinalized++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void makeRefs(FinalizableObject objects[],
|
||||
WeakReference<FinalizableObject> refs[]) {
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
objects[i] = new FinalizableObject();
|
||||
refs[i] = new WeakReference<FinalizableObject>(objects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
public void testWeakRefsAndFinalizers() throws Exception {
|
||||
final int NUM_REFS = 16;
|
||||
|
||||
FinalizableObject objects[] = new FinalizableObject[NUM_REFS];
|
||||
WeakReference<FinalizableObject> refs[] = new WeakReference[objects.length];
|
||||
int numCleared;
|
||||
|
||||
/* Create a bunch of objects and a parallel array
|
||||
* of WeakReferences.
|
||||
*/
|
||||
makeRefs(objects, refs);
|
||||
Runtime.getRuntime().gc();
|
||||
checkRefs(objects, refs);
|
||||
|
||||
/* Clear out every other strong reference.
|
||||
*/
|
||||
sNumFinalized = 0;
|
||||
numCleared = 0;
|
||||
for (int i = 0; i < objects.length; i += 2) {
|
||||
objects[i] = null;
|
||||
numCleared++;
|
||||
}
|
||||
// System.out.println("HeapTest/WeakRefsAndFinalizers: cleared evens");
|
||||
Runtime.getRuntime().gc();
|
||||
Runtime.getRuntime().runFinalization();
|
||||
checkRefs(objects, refs);
|
||||
if (sNumFinalized != numCleared) {
|
||||
throw new RuntimeException("Test failed: " +
|
||||
"expected " + numCleared + " finalizations, saw " +
|
||||
sNumFinalized);
|
||||
}
|
||||
|
||||
/* Clear out the rest of them.
|
||||
*/
|
||||
sNumFinalized = 0;
|
||||
numCleared = 0;
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (objects[i] != null) {
|
||||
objects[i] = null;
|
||||
numCleared++;
|
||||
}
|
||||
}
|
||||
// System.out.println("HeapTest/WeakRefsAndFinalizers: cleared all");
|
||||
Runtime.getRuntime().gc();
|
||||
Runtime.getRuntime().runFinalization();
|
||||
checkRefs(objects, refs);
|
||||
if (sNumFinalized != numCleared) {
|
||||
throw new RuntimeException("Test failed: " +
|
||||
"expected " + numCleared + " finalizations, saw " +
|
||||
sNumFinalized);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: flaky test
|
||||
//@MediumTest
|
||||
public void testOomeLarge() throws Exception {
|
||||
/* Just shy of the typical max heap size so that it will actually
|
||||
* try to allocate it instead of short-circuiting.
|
||||
*/
|
||||
final int SIXTEEN_MB = (16 * 1024 * 1024 - 32);
|
||||
|
||||
Boolean sawEx = false;
|
||||
byte a[];
|
||||
|
||||
try {
|
||||
a = new byte[SIXTEEN_MB];
|
||||
} catch (OutOfMemoryError oom) {
|
||||
//Log.i(TAG, "HeapTest/OomeLarge caught " + oom);
|
||||
sawEx = true;
|
||||
}
|
||||
|
||||
if (!sawEx) {
|
||||
throw new RuntimeException("Test failed: " +
|
||||
"OutOfMemoryError not thrown");
|
||||
}
|
||||
}
|
||||
|
||||
//See bug 1308253 for reasons.
|
||||
@Suppress
|
||||
public void disableTestOomeSmall() throws Exception {
|
||||
final int SIXTEEN_MB = (16 * 1024 * 1024);
|
||||
final int LINK_SIZE = 6 * 4; // estimated size of a LinkedList's node
|
||||
|
||||
Boolean sawEx = false;
|
||||
|
||||
LinkedList<Object> list = new LinkedList<Object>();
|
||||
|
||||
/* Allocate progressively smaller objects to fill up the entire heap.
|
||||
*/
|
||||
int objSize = 1 * 1024 * 1024;
|
||||
while (objSize >= LINK_SIZE) {
|
||||
try {
|
||||
for (int i = 0; i < SIXTEEN_MB / objSize; i++) {
|
||||
list.add((Object)new byte[objSize]);
|
||||
}
|
||||
} catch (OutOfMemoryError oom) {
|
||||
sawEx = true;
|
||||
}
|
||||
|
||||
if (!sawEx) {
|
||||
throw new RuntimeException("Test failed: " +
|
||||
"OutOfMemoryError not thrown while filling heap");
|
||||
}
|
||||
sawEx = false;
|
||||
|
||||
objSize = (objSize * 4) / 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user