Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: edu/emory/mathcs/util/allocator/PoolingAllocator.java


1   /* ***** BEGIN LICENSE BLOCK *****
2    * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3    *
4    * The contents of this file are subject to the Mozilla Public License Version
5    * 1.1 (the "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    * http://www.mozilla.org/MPL/
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis,
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11   * for the specific language governing rights and limitations under the
12   * License.
13   *
14   * The Original Code is the Emory Utilities.
15   *
16   * The Initial Developer of the Original Code is
17   * The Distributed Computing Laboratory, Emory University.
18   * Portions created by the Initial Developer are Copyright (C) 2002
19   * the Initial Developer. All Rights Reserved.
20   *
21   * Alternatively, the contents of this file may be used under the terms of
22   * either the GNU General Public License Version 2 or later (the "GPL"), or
23   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
24   * in which case the provisions of the GPL or the LGPL are applicable instead
25   * of those above. If you wish to allow use of your version of this file only
26   * under the terms of either the GPL or the LGPL, and not to allow others to
27   * use your version of this file under the terms of the MPL, indicate your
28   * decision by deleting the provisions above and replace them with the notice
29   * and other provisions required by the GPL or the LGPL. If you do not delete
30   * the provisions above, a recipient may use your version of this file under
31   * the terms of any one of the MPL, the GPL or the LGPL.
32   *
33   * ***** END LICENSE BLOCK ***** */
34  
35  package edu.emory.mathcs.util.allocator;
36  
37  /**
38   * Implements the {@link Allocator} using memory buffer pool. Able to enforce
39   * memory usage limits; attempts to avoid OutOfMemoryErrors by postponing the
40   * allocate requests when there is insufficient memory available in the system.
41   * Parameters of the pool are: (1) reserved capacity --
42   * if the current memory usage of the pool is below this value, the allocate
43   * request will be always attempted without blocking; (2) maximum capacity --
44   * if the allocate request would inflate the current memory usage above this
45   * value, the call will block until more memory is available; (3) security
46   * margin -- if the memory available in the system is below this value, the
47   * allocate request will block unless current usage is below reserved capacity.
48   *
49   * @author Dawid Kurzyniec
50   * @version 1.0
51   */
52  
53  public class PoolingAllocator implements Allocator {
54      final BufferPool bufpool;
55  
56      private final Runtime runtime;
57  
58      private final long reserved, max;
59      private final long minLeft;
60  
61      private long memOccupied = 0;
62  
63      // minimize freeMemory() calls
64      private long lastFreeMem = 0;
65      private long occupiedOnLastFreeMem = 0;
66  
67      /**
68       * Constructs pooling allocator with default reserved capacity of
69       * 1 MB, unlimited maximum capacity and default security margin
70       * of 2 MB.
71       */
72      public PoolingAllocator() {
73          this(1*1024*1024, -1);
74      }
75  
76     /**
77       * Constructs pooling allocator with specified reserved and maximum capacity
78       * and default security margin of 2 MB.
79       *
80       * @param reserved the reserved capacity.
81       * @param max the maximum capacity.
82       */
83      public PoolingAllocator(long reserved, long max) {
84          this(reserved, max, 2*1024*1024);
85      }
86  
87     /**
88       * Constructs pooling allocator with specified reserved and maximum capacity
89       * and specified security margin.
90       *
91       * @param reserved the reserved capacity.
92       * @param max the maximum capacity.
93       * @param minLeft the security margin.
94       */
95      public PoolingAllocator(long reserved, long max, int minLeft) {
96          this(reserved, max, minLeft, new BufferPool());
97      }
98  
99     /**
100      * Constructs pooling allocator with specified reserved and maximum capacity
101      * and specified security margin, as well as given buffer pool.
102      *
103      * @param reserved the reserved capacity.
104      * @param max the maximum capacity.
105      * @param minLeft the security margin.
106      * @param pool the buffer pool to use.
107      */
108     public PoolingAllocator(long reserved, long max, int minLeft, BufferPool bufpool) {
109         this.bufpool = bufpool;
110         this.reserved = reserved;
111         this.max = max;
112         this.minLeft = minLeft;
113         this.runtime = Runtime.getRuntime();
114     }
115 
116     public Allocator.Buffer allocate(int size, boolean clear, long timeout)
117         throws InterruptedException
118     {
119         long endTime = -1;
120         synchronized (this) {
121             while (!canAlloc(size)) {
122                 // need to wait
123                 if (timeout < 0) {
124                     // wait until notification
125                     wait();
126                 } else if (timeout == 0) {
127                     // do not wait
128                     return null;
129                 } else {
130                     // wait remaining time
131                     long remaining;
132                     if (endTime < 0) {
133                         endTime = System.currentTimeMillis() + timeout;
134                         remaining = timeout;
135                     } else {
136                         remaining = endTime - System.currentTimeMillis();
137                     }
138                     if (remaining <= 0) return null;
139                     wait(remaining);
140                 }
141             }
142 
143             // green light
144             memOccupied += size;
145 
146             // continue unsynchronized
147         }
148 
149         byte[] data = bufpool.get(size, clear);
150         Buffer buf = new Buffer(data, size);
151         if (data.length > size) {
152             synchronized (this) {
153                 memOccupied += (data.length - size);
154             }
155         }
156         return buf;
157     }
158 
159     private boolean canAlloc(int size) {
160         if (max >= 0 && memOccupied + size > max) return false;
161         if (memOccupied + size <= reserved) return true;
162         if (minLeft < 0) return true;
163         long morenew = memOccupied-occupiedOnLastFreeMem;
164         // minimize calls to freeMemory(); do it only if memory allocated
165         // since the last call exceeded 1MB or 1/16 of the remaining
166         if (morenew > 1024*1024 || morenew > lastFreeMem / 16) {
167             lastFreeMem = runtime.freeMemory();
168             occupiedOnLastFreeMem = memOccupied;
169         }
170         if (lastFreeMem >= size + minLeft) return true;
171         return false;
172     }
173 
174     private void reclaim(byte[] data) {
175         synchronized (this) {
176             memOccupied -= data.length;
177             notifyAll();
178         }
179         bufpool.reclaim(data);
180     }
181 
182     private class Buffer extends Allocator.Buffer {
183         Buffer(byte[] data, int size) {
184             super(data, size);
185         }
186         protected void reclaim() {
187             PoolingAllocator.this.reclaim(this.data);
188         }
189     }
190 }