View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.pool.impl;
19  
20  import java.util.Arrays;
21  import java.util.LinkedList;
22  import java.util.List;
23  
24  import junit.framework.TestCase;
25  
26  import org.apache.commons.pool.BasePoolableObjectFactory;
27  import org.apache.commons.pool.PoolableObjectFactory;
28  
29  /**
30   * @author Dirk Verbeeck
31   * @author Sandy McArthur
32   * @version $Revision: 1084639 $ $Date: 2011-03-23 10:02:42 -0700 (Wed, 23 Mar 2011) $
33   */
34  public class TestSoftRefOutOfMemory extends TestCase {
35      private SoftReferenceObjectPool pool;
36  
37      public TestSoftRefOutOfMemory(String testName) {
38          super(testName);
39      }
40  
41      public void tearDown() throws Exception {
42          if (pool != null) {
43              pool.close();
44              pool = null;
45          }
46          System.gc();
47      }
48  
49      public void testOutOfMemory() throws Exception {
50          pool = new SoftReferenceObjectPool(new SmallPoolableObjectFactory());
51  
52          Object obj = pool.borrowObject();
53          assertEquals("1", obj);
54          pool.returnObject(obj);
55          obj = null;
56  
57          assertEquals(1, pool.getNumIdle());
58  
59          final List garbage = new LinkedList();
60          final Runtime runtime = Runtime.getRuntime();
61          while (pool.getNumIdle() > 0) {
62              try {
63                  long freeMemory = runtime.freeMemory();
64                  if (freeMemory > Integer.MAX_VALUE) {
65                      freeMemory = Integer.MAX_VALUE;
66                  }
67                  garbage.add(new byte[Math.min(1024 * 1024, (int)freeMemory/2)]);
68              } catch (OutOfMemoryError oome) {
69                  System.gc();
70              }
71              System.gc();
72          }
73          garbage.clear();
74          System.gc();
75  
76          obj = pool.borrowObject();
77          assertEquals("2", obj);
78          pool.returnObject(obj);
79          obj = null;
80  
81          assertEquals(1, pool.getNumIdle());
82      }
83  
84      public void testOutOfMemory1000() throws Exception {
85          pool = new SoftReferenceObjectPool(new SmallPoolableObjectFactory());
86  
87          for (int i = 0 ; i < 1000 ; i++) {
88              pool.addObject();
89          }
90  
91          Object obj = pool.borrowObject();
92          assertEquals("1000", obj);
93          pool.returnObject(obj);
94          obj = null;
95  
96          assertEquals(1000, pool.getNumIdle());
97  
98          final List garbage = new LinkedList();
99          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 }