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 java.util.Arrays; 021 import java.util.LinkedList; 022 import java.util.List; 023 024 import junit.framework.TestCase; 025 026 import org.apache.commons.pool.BasePoolableObjectFactory; 027 import org.apache.commons.pool.PoolableObjectFactory; 028 029 /** 030 * @author Dirk Verbeeck 031 * @author Sandy McArthur 032 * @version $Revision: 1084639 $ $Date: 2011-03-23 10:02:42 -0700 (Wed, 23 Mar 2011) $ 033 */ 034 public class TestSoftRefOutOfMemory extends TestCase { 035 private SoftReferenceObjectPool pool; 036 037 public TestSoftRefOutOfMemory(String testName) { 038 super(testName); 039 } 040 041 public void tearDown() throws Exception { 042 if (pool != null) { 043 pool.close(); 044 pool = null; 045 } 046 System.gc(); 047 } 048 049 public void testOutOfMemory() throws Exception { 050 pool = new SoftReferenceObjectPool(new SmallPoolableObjectFactory()); 051 052 Object obj = pool.borrowObject(); 053 assertEquals("1", obj); 054 pool.returnObject(obj); 055 obj = null; 056 057 assertEquals(1, pool.getNumIdle()); 058 059 final List garbage = new LinkedList(); 060 final Runtime runtime = Runtime.getRuntime(); 061 while (pool.getNumIdle() > 0) { 062 try { 063 long freeMemory = runtime.freeMemory(); 064 if (freeMemory > Integer.MAX_VALUE) { 065 freeMemory = Integer.MAX_VALUE; 066 } 067 garbage.add(new byte[Math.min(1024 * 1024, (int)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 long freeMemory = runtime.freeMemory(); 103 if (freeMemory > Integer.MAX_VALUE) { 104 freeMemory = Integer.MAX_VALUE; 105 } 106 garbage.add(new byte[Math.min(1024 * 1024, (int)freeMemory/2)]); 107 } catch (OutOfMemoryError oome) { 108 System.gc(); 109 } 110 System.gc(); 111 } 112 garbage.clear(); 113 System.gc(); 114 115 obj = pool.borrowObject(); 116 assertEquals("1001", obj); 117 pool.returnObject(obj); 118 obj = null; 119 120 assertEquals(1, pool.getNumIdle()); 121 } 122 123 public void testOutOfMemoryLarge() throws Exception { 124 pool = new SoftReferenceObjectPool(new LargePoolableObjectFactory(1000000)); 125 126 Object obj = pool.borrowObject(); 127 assertTrue(((String)obj).startsWith("1.")); 128 pool.returnObject(obj); 129 obj = null; 130 131 assertEquals(1, pool.getNumIdle()); 132 133 final List garbage = new LinkedList(); 134 final Runtime runtime = Runtime.getRuntime(); 135 while (pool.getNumIdle() > 0) { 136 try { 137 long freeMemory = runtime.freeMemory(); 138 if (freeMemory > Integer.MAX_VALUE) { 139 freeMemory = Integer.MAX_VALUE; 140 } 141 garbage.add(new byte[Math.min(1024 * 1024, (int)freeMemory/2)]); 142 } catch (OutOfMemoryError oome) { 143 System.gc(); 144 } 145 System.gc(); 146 } 147 garbage.clear(); 148 System.gc(); 149 150 obj = pool.borrowObject(); 151 assertTrue(((String)obj).startsWith("2.")); 152 pool.returnObject(obj); 153 obj = null; 154 155 assertEquals(1, pool.getNumIdle()); 156 } 157 158 /** 159 * Makes sure an {@link OutOfMemoryError} isn't swallowed. 160 */ 161 public void testOutOfMemoryError() throws Exception { 162 pool = new SoftReferenceObjectPool(new BasePoolableObjectFactory() { 163 public Object makeObject() throws Exception { 164 throw new OutOfMemoryError(); 165 } 166 }); 167 168 try { 169 pool.borrowObject(); 170 fail("Expected out of memory."); 171 } 172 catch (OutOfMemoryError ex) { 173 // expected 174 } 175 pool.close(); 176 177 pool = new SoftReferenceObjectPool(new BasePoolableObjectFactory() { 178 public Object makeObject() throws Exception { 179 return new Object(); 180 } 181 182 public boolean validateObject(Object obj) { 183 throw new OutOfMemoryError(); 184 } 185 }); 186 187 try { 188 pool.borrowObject(); 189 fail("Expected out of memory."); 190 } 191 catch (OutOfMemoryError ex) { 192 // expected 193 } 194 pool.close(); 195 196 pool = new SoftReferenceObjectPool(new BasePoolableObjectFactory() { 197 public Object makeObject() throws Exception { 198 return new Object(); 199 } 200 201 public boolean validateObject(Object obj) { 202 throw new IllegalAccessError(); 203 } 204 205 public void destroyObject(Object obj) throws Exception { 206 throw new OutOfMemoryError(); 207 } 208 }); 209 210 try { 211 pool.borrowObject(); 212 fail("Expected out of memory."); 213 } 214 catch (OutOfMemoryError ex) { 215 // expected 216 } 217 pool.close(); 218 219 } 220 221 222 public static class SmallPoolableObjectFactory implements PoolableObjectFactory { 223 private int counter = 0; 224 225 public Object makeObject() { 226 counter++; 227 // It seems that as of Java 1.4 String.valueOf may return an 228 // intern()'ed String this may cause problems when the tests 229 // depend on the returned object to be eventually garbaged 230 // collected. Either way, making sure a new String instance 231 // is returned eliminated false failures. 232 return new String(String.valueOf(counter)); 233 } 234 public boolean validateObject(Object obj) { 235 return true; 236 } 237 public void activateObject(Object obj) { } 238 public void passivateObject(Object obj) { } 239 public void destroyObject(Object obj) { } 240 } 241 242 public static class LargePoolableObjectFactory implements PoolableObjectFactory { 243 private String buffer; 244 private int counter = 0; 245 246 public LargePoolableObjectFactory(int size) { 247 char[] data = new char[size]; 248 Arrays.fill(data, '.'); 249 buffer = new String(data); 250 } 251 252 public Object makeObject() { 253 counter++; 254 return String.valueOf(counter) + buffer; 255 } 256 public boolean validateObject(Object obj) { 257 return true; 258 } 259 public void activateObject(Object obj) { } 260 public void passivateObject(Object obj) { } 261 public void destroyObject(Object obj) { } 262 } 263 }