001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.pool.impl; 019 020 import junit.framework.TestCase; 021 import junit.framework.TestSuite; 022 import org.apache.commons.pool.BasePoolableObjectFactory; 023 import org.apache.commons.pool.PoolableObjectFactory; 024 025 import java.util.Arrays; 026 import java.util.LinkedList; 027 import java.util.List; 028 029 /** 030 * @author Dirk Verbeeck 031 * @author Sandy McArthur 032 * @version $Revision: 480413 $ $Date: 2006-11-29 00:16:05 -0500 (Wed, 29 Nov 2006) $ 033 */ 034 public class TestSoftRefOutOfMemory extends TestCase { 035 private SoftReferenceObjectPool pool; 036 037 public TestSoftRefOutOfMemory(String testName) { 038 super(testName); 039 } 040 041 public static TestSuite suite() { 042 return new TestSuite(TestSoftRefOutOfMemory.class); 043 } 044 045 public void tearDown() throws Exception { 046 if (pool != null) { 047 pool.close(); 048 pool = null; 049 } 050 System.gc(); 051 } 052 053 public void testOutOfMemory() throws Exception { 054 pool = new SoftReferenceObjectPool(new SmallPoolableObjectFactory()); 055 056 Object obj = pool.borrowObject(); 057 assertEquals("1", obj); 058 pool.returnObject(obj); 059 obj = null; 060 061 assertEquals(1, pool.getNumIdle()); 062 063 final List garbage = new LinkedList(); 064 final Runtime runtime = Runtime.getRuntime(); 065 while (pool.getNumIdle() > 0) { 066 try { 067 garbage.add(new byte[Math.min(1024 * 1024, (int)runtime.freeMemory()/2)]); 068 } catch (OutOfMemoryError oome) { 069 System.gc(); 070 } 071 System.gc(); 072 } 073 garbage.clear(); 074 System.gc(); 075 076 obj = pool.borrowObject(); 077 assertEquals("2", obj); 078 pool.returnObject(obj); 079 obj = null; 080 081 assertEquals(1, pool.getNumIdle()); 082 } 083 084 public void testOutOfMemory1000() throws Exception { 085 pool = new SoftReferenceObjectPool(new SmallPoolableObjectFactory()); 086 087 for (int i = 0 ; i < 1000 ; i++) { 088 pool.addObject(); 089 } 090 091 Object obj = pool.borrowObject(); 092 assertEquals("1000", obj); 093 pool.returnObject(obj); 094 obj = null; 095 096 assertEquals(1000, pool.getNumIdle()); 097 098 final List garbage = new LinkedList(); 099 final Runtime runtime = Runtime.getRuntime(); 100 while (pool.getNumIdle() > 0) { 101 try { 102 garbage.add(new byte[Math.min(1024 * 1024, (int)runtime.freeMemory()/2)]); 103 } catch (OutOfMemoryError oome) { 104 System.gc(); 105 } 106 System.gc(); 107 } 108 garbage.clear(); 109 System.gc(); 110 111 obj = pool.borrowObject(); 112 assertEquals("1001", obj); 113 pool.returnObject(obj); 114 obj = null; 115 116 assertEquals(1, pool.getNumIdle()); 117 } 118 119 public void testOutOfMemoryLarge() throws Exception { 120 pool = new SoftReferenceObjectPool(new LargePoolableObjectFactory(1000000)); 121 122 Object obj = pool.borrowObject(); 123 assertTrue(((String)obj).startsWith("1.")); 124 pool.returnObject(obj); 125 obj = null; 126 127 assertEquals(1, pool.getNumIdle()); 128 129 final List garbage = new LinkedList(); 130 final Runtime runtime = Runtime.getRuntime(); 131 while (pool.getNumIdle() > 0) { 132 try { 133 garbage.add(new byte[Math.min(1024 * 1024, (int)runtime.freeMemory()/2)]); 134 } catch (OutOfMemoryError oome) { 135 System.gc(); 136 } 137 System.gc(); 138 } 139 garbage.clear(); 140 System.gc(); 141 142 obj = pool.borrowObject(); 143 assertTrue(((String)obj).startsWith("2.")); 144 pool.returnObject(obj); 145 obj = null; 146 147 assertEquals(1, pool.getNumIdle()); 148 } 149 150 /** 151 * Makes sure an {@link OutOfMemoryError} isn't swallowed. 152 */ 153 public void testOutOfMemoryError() throws Exception { 154 pool = new SoftReferenceObjectPool(new BasePoolableObjectFactory() { 155 public Object makeObject() throws Exception { 156 throw new OutOfMemoryError(); 157 } 158 }); 159 160 try { 161 pool.borrowObject(); 162 fail("Expected out of memory."); 163 } 164 catch (OutOfMemoryError ex) { 165 // expected 166 } 167 pool.close(); 168 169 pool = new SoftReferenceObjectPool(new BasePoolableObjectFactory() { 170 public Object makeObject() throws Exception { 171 return new Object(); 172 } 173 174 public boolean validateObject(Object obj) { 175 throw new OutOfMemoryError(); 176 } 177 }); 178 179 pool.returnObject(pool.borrowObject()); 180 181 try { 182 pool.borrowObject(); 183 fail("Expected out of memory."); 184 } 185 catch (OutOfMemoryError ex) { 186 // expected 187 } 188 pool.close(); 189 } 190 191 192 public static class SmallPoolableObjectFactory implements PoolableObjectFactory { 193 private int counter = 0; 194 195 public Object makeObject() { 196 counter++; 197 // It seems that as of Java 1.4 String.valueOf may return an 198 // intern()'ed String this may cause problems when the tests 199 // depend on the returned object to be eventually garbaged 200 // collected. Either way, making sure a new String instance 201 // is returned eliminated false failures. 202 return new String(String.valueOf(counter)); 203 } 204 public boolean validateObject(Object obj) { 205 return true; 206 } 207 public void activateObject(Object obj) { } 208 public void passivateObject(Object obj) { } 209 public void destroyObject(Object obj) { } 210 } 211 212 public static class LargePoolableObjectFactory implements PoolableObjectFactory { 213 private String buffer; 214 private int counter = 0; 215 216 public LargePoolableObjectFactory(int size) { 217 char[] data = new char[size]; 218 Arrays.fill(data, '.'); 219 buffer = new String(data); 220 } 221 222 public Object makeObject() { 223 counter++; 224 return String.valueOf(counter) + buffer; 225 } 226 public boolean validateObject(Object obj) { 227 return true; 228 } 229 public void activateObject(Object obj) { } 230 public void passivateObject(Object obj) { } 231 public void destroyObject(Object obj) { } 232 } 233 }