The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2007 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.unit_tests; |
| 18 | |
| 19 | import android.test.suitebuilder.annotation.LargeTest; |
| 20 | import android.test.suitebuilder.annotation.MediumTest; |
| 21 | import android.test.suitebuilder.annotation.SmallTest; |
| 22 | import android.util.Log; |
| 23 | import android.test.suitebuilder.annotation.Suppress; |
| 24 | import dalvik.system.VMRuntime; |
| 25 | import junit.framework.TestCase; |
| 26 | |
| 27 | import java.lang.ref.PhantomReference; |
| 28 | import java.lang.ref.ReferenceQueue; |
| 29 | import java.lang.ref.SoftReference; |
| 30 | import java.lang.ref.WeakReference; |
| 31 | import java.util.LinkedList; |
| 32 | import java.util.Random; |
| 33 | |
| 34 | |
| 35 | public class HeapTest extends TestCase { |
| 36 | |
| 37 | private static final String TAG = "HeapTest"; |
| 38 | |
| 39 | /** |
| 40 | * Returns a WeakReference to an object that has no |
| 41 | * other references. This is done in a separate method |
| 42 | * to ensure that the Object's address isn't sitting in |
| 43 | * a stale local register. |
| 44 | */ |
| 45 | private WeakReference<Object> newRef() { |
| 46 | return new WeakReference<Object>(new Object()); |
| 47 | } |
| 48 | |
| 49 | /** |
| 50 | * Allocates the specified number of bytes. This is done in a separate method |
| 51 | * to ensure that the Object's address isn't sitting in a stale local register. |
| 52 | */ |
| 53 | private void allocateMemory(int size) { |
| 54 | byte[] b = new byte[size]; |
| 55 | } |
| 56 | |
| 57 | @MediumTest |
| 58 | public void testMinimumHeapSize() throws Exception { |
| 59 | VMRuntime r = VMRuntime.getRuntime(); |
| 60 | final boolean RUN_FLAKY = false; |
| 61 | |
| 62 | long origSize = r.getMinimumHeapSize(); |
| 63 | if (RUN_FLAKY) { |
| 64 | /* Check that the default value is zero. This will break if anyone |
| 65 | * in this process sets the minimum heap size to a positive value |
| 66 | * before calling this test. |
| 67 | */ |
| 68 | assertTrue(origSize == 0); |
| 69 | } |
| 70 | |
| 71 | long size = 4 * 1024 * 1024; |
| 72 | long oldSize = r.setMinimumHeapSize(size); |
| 73 | assertTrue(oldSize == origSize); |
| 74 | |
| 75 | long newSize = r.getMinimumHeapSize(); |
| 76 | /* This will fail if the maximum heap size (-Xmx) is smaller than 4MB. |
| 77 | */ |
| 78 | assertTrue(newSize == size); |
| 79 | |
| 80 | /* Make sure that getting the size doesn't change anything. |
| 81 | */ |
| 82 | newSize = r.getMinimumHeapSize(); |
| 83 | assertTrue(newSize == size); |
| 84 | |
| 85 | /* This test is flaky; if the heap is already large and fragmented, |
| 86 | * it can fail. It can also fail if another thread causes a GC |
| 87 | * at the wrong time. |
| 88 | */ |
| 89 | if (RUN_FLAKY) { |
| 90 | /* Increase the minimum size, allocate a big object, and make sure that |
| 91 | * a GC didn't happen. |
| 92 | */ |
| 93 | WeakReference ref = newRef(); |
| 94 | assertNotNull(ref.get()); |
| 95 | |
| 96 | r.setMinimumHeapSize(8 * 1024 * 1024); |
| 97 | allocateMemory(4 * 1024 * 1024); |
| 98 | |
| 99 | /* If a GC happened, this reference will be null. |
| 100 | */ |
| 101 | assertNotNull(ref.get()); |
| 102 | } |
| 103 | |
| 104 | /* Restore the original setting. |
| 105 | */ |
| 106 | r.setMinimumHeapSize(origSize); |
| 107 | newSize = r.getMinimumHeapSize(); |
| 108 | assertTrue(newSize == origSize); |
| 109 | |
| 110 | /* Clean up any large stuff we've allocated, |
| 111 | * and re-establish the normal utilization ratio. |
| 112 | */ |
| 113 | Runtime.getRuntime().gc(); |
| 114 | } |
| 115 | |
| 116 | private static void makeRefs(Object objects[], SoftReference<Object> refs[]) { |
| 117 | for (int i = 0; i < objects.length; i++) { |
| 118 | objects[i] = (Object) new byte[8 * 1024]; |
| 119 | refs[i] = new SoftReference<Object>(objects[i]); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | private static <T> int checkRefs(SoftReference<T> refs[], int last) { |
| 124 | int i; |
| 125 | int numCleared = 0; |
| 126 | for (i = 0; i < refs.length; i++) { |
| 127 | Object o = refs[i].get(); |
| 128 | if (o == null) { |
| 129 | numCleared++; |
| 130 | } |
| 131 | } |
| 132 | if (numCleared != last) { |
| 133 | Log.i(TAG, "****** " + numCleared + "/" + i + " cleared ******"); |
| 134 | } |
| 135 | return numCleared; |
| 136 | } |
| 137 | |
| 138 | private static void clearRefs(Object objects[], int skip) { |
| 139 | for (int i = 0; i < objects.length; i += skip) { |
| 140 | objects[i] = null; |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | private static void clearRefs(Object objects[]) { |
| 145 | clearRefs(objects, 1); |
| 146 | } |
| 147 | |
| 148 | private static <T> void checkRefs(T objects[], SoftReference<T> refs[]) { |
| 149 | boolean ok = true; |
| 150 | |
| 151 | for (int i = 0; i < objects.length; i++) { |
| 152 | if (refs[i].get() != objects[i]) { |
| 153 | ok = false; |
| 154 | } |
| 155 | } |
| 156 | if (!ok) { |
| 157 | throw new RuntimeException("Test failed: soft refs not cleared"); |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | @MediumTest |
| 162 | public void testGcSoftRefs() throws Exception { |
| 163 | final int NUM_REFS = 128; |
| 164 | |
| 165 | Object objects[] = new Object[NUM_REFS]; |
| 166 | SoftReference<Object> refs[] = new SoftReference[objects.length]; |
| 167 | |
| 168 | /* Create a bunch of objects and a parallel array |
| 169 | * of SoftReferences. |
| 170 | */ |
| 171 | makeRefs(objects, refs); |
| 172 | Runtime.getRuntime().gc(); |
| 173 | |
| 174 | /* Let go of some of the hard references to the objects so that |
| 175 | * the references can be cleared. |
| 176 | */ |
| 177 | clearRefs(objects, 3); |
| 178 | |
| 179 | /* Collect all softly-reachable objects. |
| 180 | */ |
| 181 | VMRuntime.getRuntime().gcSoftReferences(); |
| 182 | Runtime.getRuntime().runFinalization(); |
| 183 | |
| 184 | /* Make sure that the objects were collected. |
| 185 | */ |
| 186 | checkRefs(objects, refs); |
| 187 | |
| 188 | /* Remove more hard references and re-check. |
| 189 | */ |
| 190 | clearRefs(objects, 2); |
| 191 | VMRuntime.getRuntime().gcSoftReferences(); |
| 192 | Runtime.getRuntime().runFinalization(); |
| 193 | checkRefs(objects, refs); |
| 194 | |
| 195 | /* Remove the rest of the references and re-check. |
| 196 | */ |
| 197 | /* Remove more hard references and re-check. |
| 198 | */ |
| 199 | clearRefs(objects); |
| 200 | VMRuntime.getRuntime().gcSoftReferences(); |
| 201 | Runtime.getRuntime().runFinalization(); |
| 202 | checkRefs(objects, refs); |
| 203 | } |
| 204 | |
| 205 | public void xxtestSoftRefPartialClean() throws Exception { |
| 206 | final int NUM_REFS = 128; |
| 207 | |
| 208 | Object objects[] = new Object[NUM_REFS]; |
| 209 | SoftReference<Object> refs[] = new SoftReference[objects.length]; |
| 210 | |
| 211 | /* Create a bunch of objects and a parallel array |
| 212 | * of SoftReferences. |
| 213 | */ |
| 214 | makeRefs(objects, refs); |
| 215 | Runtime.getRuntime().gc(); |
| 216 | |
| 217 | /* Let go of the hard references to the objects so that |
| 218 | * the references can be cleared. |
| 219 | */ |
| 220 | clearRefs(objects); |
| 221 | |
| 222 | /* Start creating a bunch of temporary and permanent objects |
| 223 | * to drive GC. |
| 224 | */ |
| 225 | final int NUM_OBJECTS = 64 * 1024; |
| 226 | Object junk[] = new Object[NUM_OBJECTS]; |
| 227 | Random random = new Random(); |
| 228 | |
| 229 | int i = 0; |
| 230 | int mod = 0; |
| 231 | int totalSize = 0; |
| 232 | int cleared = -1; |
| 233 | while (i < junk.length && totalSize < 8 * 1024 * 1024) { |
| 234 | int r = random.nextInt(64 * 1024) + 128; |
| 235 | Object o = (Object) new byte[r]; |
| 236 | if (++mod % 16 == 0) { |
| 237 | junk[i++] = o; |
| 238 | totalSize += r * 4; |
| 239 | } |
| 240 | cleared = checkRefs(refs, cleared); |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | private static void makeRefs(Object objects[], WeakReference<Object> refs[]) { |
| 245 | for (int i = 0; i < objects.length; i++) { |
| 246 | objects[i] = new Object(); |
| 247 | refs[i] = new WeakReference<Object>(objects[i]); |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | private static <T> void checkRefs(T objects[], WeakReference<T> refs[]) { |
| 252 | boolean ok = true; |
| 253 | |
| 254 | for (int i = 0; i < objects.length; i++) { |
| 255 | if (refs[i].get() != objects[i]) { |
| 256 | ok = false; |
| 257 | } |
| 258 | } |
| 259 | if (!ok) { |
| 260 | throw new RuntimeException("Test failed: " + |
| 261 | "weak refs not cleared"); |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | @MediumTest |
| 266 | public void testWeakRefs() throws Exception { |
| 267 | final int NUM_REFS = 16; |
| 268 | |
| 269 | Object objects[] = new Object[NUM_REFS]; |
| 270 | WeakReference<Object> refs[] = new WeakReference[objects.length]; |
| 271 | |
| 272 | /* Create a bunch of objects and a parallel array |
| 273 | * of WeakReferences. |
| 274 | */ |
| 275 | makeRefs(objects, refs); |
| 276 | Runtime.getRuntime().gc(); |
| 277 | checkRefs(objects, refs); |
| 278 | |
| 279 | /* Clear out every other strong reference. |
| 280 | */ |
| 281 | for (int i = 0; i < objects.length; i += 2) { |
| 282 | objects[i] = null; |
| 283 | } |
| 284 | Runtime.getRuntime().gc(); |
| 285 | checkRefs(objects, refs); |
| 286 | |
| 287 | /* Clear out the rest of them. |
| 288 | */ |
| 289 | for (int i = 0; i < objects.length; i++) { |
| 290 | objects[i] = null; |
| 291 | } |
| 292 | Runtime.getRuntime().gc(); |
| 293 | checkRefs(objects, refs); |
| 294 | } |
| 295 | |
| 296 | private static void makeRefs(Object objects[], PhantomReference<Object> refs[], |
| 297 | ReferenceQueue<Object> queue) { |
| 298 | for (int i = 0; i < objects.length; i++) { |
| 299 | objects[i] = new Object(); |
| 300 | refs[i] = new PhantomReference<Object>(objects[i], queue); |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | static <T> void checkRefs(T objects[], PhantomReference<T> refs[], |
| 305 | ReferenceQueue<T> queue) { |
| 306 | boolean ok = true; |
| 307 | |
| 308 | /* Make sure that the reference that should be on |
| 309 | * the queue are marked as enqueued. Once we |
| 310 | * pull them off the queue, they will no longer |
| 311 | * be marked as enqueued. |
| 312 | */ |
| 313 | for (int i = 0; i < objects.length; i++) { |
| 314 | if (objects[i] == null && refs[i] != null) { |
| 315 | if (!refs[i].isEnqueued()) { |
| 316 | ok = false; |
| 317 | } |
| 318 | } |
| 319 | } |
| 320 | if (!ok) { |
| 321 | throw new RuntimeException("Test failed: " + |
| 322 | "phantom refs not marked as enqueued"); |
| 323 | } |
| 324 | |
| 325 | /* Make sure that all of the references on the queue |
| 326 | * are supposed to be there. |
| 327 | */ |
| 328 | PhantomReference<T> ref; |
| 329 | while ((ref = (PhantomReference<T>) queue.poll()) != null) { |
| 330 | /* Find the list index that corresponds to this reference. |
| 331 | */ |
| 332 | int i; |
| 333 | for (i = 0; i < objects.length; i++) { |
| 334 | if (refs[i] == ref) { |
| 335 | break; |
| 336 | } |
| 337 | } |
| 338 | if (i == objects.length) { |
| 339 | throw new RuntimeException("Test failed: " + |
| 340 | "unexpected ref on queue"); |
| 341 | } |
| 342 | if (objects[i] != null) { |
| 343 | throw new RuntimeException("Test failed: " + |
| 344 | "reference enqueued for strongly-reachable " + |
| 345 | "object"); |
| 346 | } |
| 347 | refs[i] = null; |
| 348 | |
| 349 | /* TODO: clear doesn't do much, since we're losing the |
| 350 | * strong ref to the ref object anyway. move the ref |
| 351 | * into another list. |
| 352 | */ |
| 353 | ref.clear(); |
| 354 | } |
| 355 | |
| 356 | /* We've visited all of the enqueued references. |
| 357 | * Make sure that there aren't any other references |
| 358 | * that should have been enqueued. |
| 359 | * |
| 360 | * NOTE: there is a race condition here; this assumes |
| 361 | * that the VM has serviced all outstanding reference |
| 362 | * enqueue() calls. |
| 363 | */ |
| 364 | for (int i = 0; i < objects.length; i++) { |
| 365 | if (objects[i] == null && refs[i] != null) { |
| 366 | // System.out.println("HeapTest/PhantomRefs: refs[" + i + |
| 367 | // "] should be enqueued"); |
| 368 | ok = false; |
| 369 | } |
| 370 | } |
| 371 | if (!ok) { |
| 372 | throw new RuntimeException("Test failed: " + |
| 373 | "phantom refs not enqueued"); |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | @MediumTest |
| 378 | public void testPhantomRefs() throws Exception { |
| 379 | final int NUM_REFS = 16; |
| 380 | |
| 381 | Object objects[] = new Object[NUM_REFS]; |
| 382 | PhantomReference<Object> refs[] = new PhantomReference[objects.length]; |
| 383 | ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); |
| 384 | |
| 385 | /* Create a bunch of objects and a parallel array |
| 386 | * of PhantomReferences. |
| 387 | */ |
| 388 | makeRefs(objects, refs, queue); |
| 389 | Runtime.getRuntime().gc(); |
| 390 | checkRefs(objects, refs, queue); |
| 391 | |
| 392 | /* Clear out every other strong reference. |
| 393 | */ |
| 394 | for (int i = 0; i < objects.length; i += 2) { |
| 395 | objects[i] = null; |
| 396 | } |
| 397 | // System.out.println("HeapTest/PhantomRefs: cleared evens"); |
| 398 | Runtime.getRuntime().gc(); |
| 399 | Runtime.getRuntime().runFinalization(); |
| 400 | checkRefs(objects, refs, queue); |
| 401 | |
| 402 | /* Clear out the rest of them. |
| 403 | */ |
| 404 | for (int i = 0; i < objects.length; i++) { |
| 405 | objects[i] = null; |
| 406 | } |
| 407 | // System.out.println("HeapTest/PhantomRefs: cleared all"); |
| 408 | Runtime.getRuntime().gc(); |
| 409 | Runtime.getRuntime().runFinalization(); |
| 410 | checkRefs(objects, refs, queue); |
| 411 | } |
| 412 | |
| 413 | private static int sNumFinalized = 0; |
| 414 | private static final Object sLock = new Object(); |
| 415 | |
| 416 | private static class FinalizableObject { |
| 417 | protected void finalize() { |
| 418 | // System.out.println("gc from finalize()"); |
| 419 | Runtime.getRuntime().gc(); |
| 420 | synchronized (sLock) { |
| 421 | sNumFinalized++; |
| 422 | } |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | private static void makeRefs(FinalizableObject objects[], |
| 427 | WeakReference<FinalizableObject> refs[]) { |
| 428 | for (int i = 0; i < objects.length; i++) { |
| 429 | objects[i] = new FinalizableObject(); |
| 430 | refs[i] = new WeakReference<FinalizableObject>(objects[i]); |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | @LargeTest |
| 435 | public void testWeakRefsAndFinalizers() throws Exception { |
| 436 | final int NUM_REFS = 16; |
| 437 | |
| 438 | FinalizableObject objects[] = new FinalizableObject[NUM_REFS]; |
| 439 | WeakReference<FinalizableObject> refs[] = new WeakReference[objects.length]; |
| 440 | int numCleared; |
| 441 | |
| 442 | /* Create a bunch of objects and a parallel array |
| 443 | * of WeakReferences. |
| 444 | */ |
| 445 | makeRefs(objects, refs); |
| 446 | Runtime.getRuntime().gc(); |
| 447 | checkRefs(objects, refs); |
| 448 | |
| 449 | /* Clear out every other strong reference. |
| 450 | */ |
| 451 | sNumFinalized = 0; |
| 452 | numCleared = 0; |
| 453 | for (int i = 0; i < objects.length; i += 2) { |
| 454 | objects[i] = null; |
| 455 | numCleared++; |
| 456 | } |
| 457 | // System.out.println("HeapTest/WeakRefsAndFinalizers: cleared evens"); |
| 458 | Runtime.getRuntime().gc(); |
| 459 | Runtime.getRuntime().runFinalization(); |
| 460 | checkRefs(objects, refs); |
| 461 | if (sNumFinalized != numCleared) { |
| 462 | throw new RuntimeException("Test failed: " + |
| 463 | "expected " + numCleared + " finalizations, saw " + |
| 464 | sNumFinalized); |
| 465 | } |
| 466 | |
| 467 | /* Clear out the rest of them. |
| 468 | */ |
| 469 | sNumFinalized = 0; |
| 470 | numCleared = 0; |
| 471 | for (int i = 0; i < objects.length; i++) { |
| 472 | if (objects[i] != null) { |
| 473 | objects[i] = null; |
| 474 | numCleared++; |
| 475 | } |
| 476 | } |
| 477 | // System.out.println("HeapTest/WeakRefsAndFinalizers: cleared all"); |
| 478 | Runtime.getRuntime().gc(); |
| 479 | Runtime.getRuntime().runFinalization(); |
| 480 | checkRefs(objects, refs); |
| 481 | if (sNumFinalized != numCleared) { |
| 482 | throw new RuntimeException("Test failed: " + |
| 483 | "expected " + numCleared + " finalizations, saw " + |
| 484 | sNumFinalized); |
| 485 | } |
| 486 | } |
| 487 | |
Brett Chabot | b8a4e5f | 2009-10-06 19:13:31 -0700 | [diff] [blame] | 488 | // TODO: flaky test |
| 489 | //@MediumTest |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 490 | public void testOomeLarge() throws Exception { |
| 491 | /* Just shy of the typical max heap size so that it will actually |
| 492 | * try to allocate it instead of short-circuiting. |
| 493 | */ |
| 494 | final int SIXTEEN_MB = (16 * 1024 * 1024 - 32); |
| 495 | |
| 496 | Boolean sawEx = false; |
| 497 | byte a[]; |
| 498 | |
| 499 | try { |
| 500 | a = new byte[SIXTEEN_MB]; |
| 501 | } catch (OutOfMemoryError oom) { |
| 502 | //Log.i(TAG, "HeapTest/OomeLarge caught " + oom); |
| 503 | sawEx = true; |
| 504 | } |
| 505 | |
| 506 | if (!sawEx) { |
| 507 | throw new RuntimeException("Test failed: " + |
| 508 | "OutOfMemoryError not thrown"); |
| 509 | } |
| 510 | } |
| 511 | |
| 512 | //See bug 1308253 for reasons. |
| 513 | @Suppress |
| 514 | public void disableTestOomeSmall() throws Exception { |
| 515 | final int SIXTEEN_MB = (16 * 1024 * 1024); |
| 516 | final int LINK_SIZE = 6 * 4; // estimated size of a LinkedList's node |
| 517 | |
| 518 | Boolean sawEx = false; |
| 519 | |
| 520 | LinkedList<Object> list = new LinkedList<Object>(); |
| 521 | |
| 522 | /* Allocate progressively smaller objects to fill up the entire heap. |
| 523 | */ |
| 524 | int objSize = 1 * 1024 * 1024; |
| 525 | while (objSize >= LINK_SIZE) { |
| 526 | try { |
| 527 | for (int i = 0; i < SIXTEEN_MB / objSize; i++) { |
| 528 | list.add((Object)new byte[objSize]); |
| 529 | } |
| 530 | } catch (OutOfMemoryError oom) { |
| 531 | sawEx = true; |
| 532 | } |
| 533 | |
| 534 | if (!sawEx) { |
| 535 | throw new RuntimeException("Test failed: " + |
| 536 | "OutOfMemoryError not thrown while filling heap"); |
| 537 | } |
| 538 | sawEx = false; |
| 539 | |
| 540 | objSize = (objSize * 4) / 5; |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | @SmallTest |
| 545 | public void testExternalOomeLarge() { |
| 546 | /* Just shy of the typical max heap size so that it will actually |
| 547 | * try to allocate it instead of short-circuiting. |
| 548 | */ |
| 549 | final int HUGE_SIZE = (16 * 1024 * 1024 - 32); |
| 550 | |
| 551 | assertFalse(VMRuntime.getRuntime().trackExternalAllocation(HUGE_SIZE)); |
| 552 | } |
| 553 | |
| 554 | /** |
| 555 | * "Allocates" external memory in progressively smaller chunks until there's |
| 556 | * only roughly 16 bytes left. |
| 557 | * |
| 558 | * @return the number of bytes allocated |
| 559 | */ |
| 560 | private long allocateMaxExternal() { |
| 561 | final VMRuntime runtime = VMRuntime.getRuntime(); |
| 562 | final int SIXTEEN_MB = (16 * 1024 * 1024); |
| 563 | final int MIN_SIZE = 16; |
| 564 | long totalAllocated = 0; |
| 565 | boolean success; |
| 566 | |
| 567 | success = false; |
| 568 | try { |
| 569 | /* "Allocate" progressively smaller chunks to "fill up" the entire heap. |
| 570 | */ |
| 571 | int objSize = 1 * 1024 * 1024; |
| 572 | while (objSize >= MIN_SIZE) { |
| 573 | boolean sawFailure = false; |
| 574 | for (int i = 0; i < SIXTEEN_MB / objSize; i++) { |
| 575 | if (runtime.trackExternalAllocation(objSize)) { |
| 576 | totalAllocated += objSize; |
| 577 | } else { |
| 578 | sawFailure = true; |
| 579 | break; |
| 580 | } |
| 581 | } |
| 582 | |
| 583 | if (!sawFailure) { |
| 584 | throw new RuntimeException("Test failed: " + |
| 585 | "no failure while filling heap"); |
| 586 | } |
| 587 | |
| 588 | objSize = (objSize * 4) / 5; |
| 589 | } |
| 590 | success = true; |
| 591 | } finally { |
| 592 | if (!success) { |
| 593 | runtime.trackExternalFree(totalAllocated); |
| 594 | totalAllocated = 0; |
| 595 | } |
| 596 | } |
| 597 | return totalAllocated; |
| 598 | } |
| 599 | |
| 600 | public void xxtest00ExternalOomeSmall() { |
| 601 | VMRuntime.getRuntime().trackExternalFree(allocateMaxExternal()); |
| 602 | } |
| 603 | |
| 604 | /** |
| 605 | * Allocates as much external memory as possible, then allocates from the heap |
| 606 | * until an OOME is caught. |
| 607 | * |
| 608 | * It's nice to run this test while the real heap is small, hence the '00' in its |
| 609 | * name to force it to run before testOomeSmall(). |
| 610 | */ |
| 611 | public void xxtest00CombinedOomeSmall() { |
| 612 | long totalAllocated = 0; |
| 613 | boolean sawEx = false; |
| 614 | try { |
| 615 | totalAllocated = allocateMaxExternal(); |
| 616 | LinkedList<Object> list = new LinkedList<Object>(); |
| 617 | try { |
| 618 | while (true) { |
| 619 | list.add((Object)new byte[8192]); |
| 620 | } |
| 621 | /*NOTREACHED*/ |
| 622 | } catch (OutOfMemoryError oom) { |
| 623 | sawEx = true; |
| 624 | } |
| 625 | } finally { |
| 626 | VMRuntime.getRuntime().trackExternalFree(totalAllocated); |
| 627 | } |
| 628 | assertTrue(sawEx); |
| 629 | } |
| 630 | |
| 631 | //TODO: test external alloc debugging/inspection |
| 632 | } |