• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package java.nio;
28 
29 import java.security.AccessController;
30 
31 import sun.misc.VM;
32 import jdk.internal.access.SharedSecrets;
33 import jdk.internal.misc.Unsafe;
34 
35 import java.util.concurrent.atomic.AtomicLong;
36 
37 /**
38  * Access to bits, native and otherwise.
39  */
40 
41 class Bits {                            // package-private
42 
Bits()43     private Bits() { }
44 
45 
46     // -- Swapping --
47 
swap(short x)48     static short swap(short x) {
49         return Short.reverseBytes(x);
50     }
51 
swap(char x)52     static char swap(char x) {
53         return Character.reverseBytes(x);
54     }
55 
swap(int x)56     static int swap(int x) {
57         return Integer.reverseBytes(x);
58     }
59 
swap(long x)60     static long swap(long x) {
61         return Long.reverseBytes(x);
62     }
63 
64 
65     // -- Unsafe access --
66 
67     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
68 
69     // -- Processor and memory-system properties --
70 
71     private static int PAGE_SIZE = -1;
72 
pageSize()73     static int pageSize() {
74         if (PAGE_SIZE == -1)
75             PAGE_SIZE = UNSAFE.pageSize();
76         return PAGE_SIZE;
77     }
78 
pageCount(long size)79     static long pageCount(long size) {
80         return (size + (long)pageSize() - 1L) / pageSize();
81     }
82     // Android-removed: Remove unused methods.
83     /*
84     private static boolean UNALIGNED = UNSAFE.unalignedAccess();
85 
86     static boolean unaligned() {
87         return UNALIGNED;
88     }
89     */
90 
91 
92     // -- Direct memory management --
93 
94     // BEGIN Android-removed: Direct memory management unused on Android.
95     /*
96     // A user-settable upper limit on the maximum amount of allocatable
97     // direct buffer memory.  This value may be changed during VM
98     // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
99     private static volatile long MAX_MEMORY = VM.maxDirectMemory();
100     private static final AtomicLong RESERVED_MEMORY = new AtomicLong();
101     private static final AtomicLong TOTAL_CAPACITY = new AtomicLong();
102     private static final AtomicLong COUNT = new AtomicLong();
103     private static volatile boolean MEMORY_LIMIT_SET;
104 
105     // max. number of sleeps during try-reserving with exponentially
106     // increasing delay before throwing OutOfMemoryError:
107     // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
108     // which means that OOME will be thrown after 0.5 s of trying
109     private static final int MAX_SLEEPS = 9;
110 
111     // These methods should be called whenever direct memory is allocated or
112     // freed.  They allow the user to control the amount of direct memory
113     // which a process may access.  All sizes are specified in bytes.
114     static void reserveMemory(long size, long cap) {
115 
116         if (!MEMORY_LIMIT_SET && VM.initLevel() >= 1) {
117             MAX_MEMORY = VM.maxDirectMemory();
118             MEMORY_LIMIT_SET = true;
119         }
120 
121         // optimist!
122         if (tryReserveMemory(size, cap)) {
123             return;
124         }
125 
126         final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
127         boolean interrupted = false;
128         try {
129 
130             // Retry allocation until success or there are no more
131             // references (including Cleaners that might free direct
132             // buffer memory) to process and allocation still fails.
133             boolean refprocActive;
134             do {
135                 try {
136                     refprocActive = jlra.waitForReferenceProcessing();
137                 } catch (InterruptedException e) {
138                     // Defer interrupts and keep trying.
139                     interrupted = true;
140                     refprocActive = true;
141                 }
142                 if (tryReserveMemory(size, cap)) {
143                     return;
144                 }
145             } while (refprocActive);
146 
147             // trigger VM's Reference processing
148             System.gc();
149 
150             // A retry loop with exponential back-off delays.
151             // Sometimes it would suffice to give up once reference
152             // processing is complete.  But if there are many threads
153             // competing for memory, this gives more opportunities for
154             // any given thread to make progress.  In particular, this
155             // seems to be enough for a stress test like
156             // DirectBufferAllocTest to (usually) succeed, while
157             // without it that test likely fails.  Since failure here
158             // ends in OOME, there's no need to hurry.
159             long sleepTime = 1;
160             int sleeps = 0;
161             while (true) {
162                 if (tryReserveMemory(size, cap)) {
163                     return;
164                 }
165                 if (sleeps >= MAX_SLEEPS) {
166                     break;
167                 }
168                 try {
169                     if (!jlra.waitForReferenceProcessing()) {
170                         Thread.sleep(sleepTime);
171                         sleepTime <<= 1;
172                         sleeps++;
173                     }
174                 } catch (InterruptedException e) {
175                     interrupted = true;
176                 }
177             }
178 
179             // no luck
180             throw new OutOfMemoryError
181                 ("Cannot reserve "
182                  + size + " bytes of direct buffer memory (allocated: "
183                  + RESERVED_MEMORY.get() + ", limit: " + MAX_MEMORY +")");
184 
185         } finally {
186             if (interrupted) {
187                 // don't swallow interrupts
188                 Thread.currentThread().interrupt();
189             }
190         }
191     }
192 
193     private static boolean tryReserveMemory(long size, long cap) {
194 
195         // -XX:MaxDirectMemorySize limits the total capacity rather than the
196         // actual memory usage, which will differ when buffers are page
197         // aligned.
198         long totalCap;
199         while (cap <= MAX_MEMORY - (totalCap = TOTAL_CAPACITY.get())) {
200             if (TOTAL_CAPACITY.compareAndSet(totalCap, totalCap + cap)) {
201                 RESERVED_MEMORY.addAndGet(size);
202                 COUNT.incrementAndGet();
203                 return true;
204             }
205         }
206 
207         return false;
208     }
209 
210 
211     static void unreserveMemory(long size, long cap) {
212         long cnt = COUNT.decrementAndGet();
213         long reservedMem = RESERVED_MEMORY.addAndGet(-size);
214         long totalCap = TOTAL_CAPACITY.addAndGet(-cap);
215         assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
216     }
217 
218     static final BufferPool BUFFER_POOL = new BufferPool() {
219         @Override
220         public String getName() {
221             return "direct";
222         }
223         @Override
224         public long getCount() {
225             return Bits.COUNT.get();
226         }
227         @Override
228         public long getTotalCapacity() {
229             return Bits.TOTAL_CAPACITY.get();
230         }
231         @Override
232         public long getMemoryUsed() {
233             return Bits.RESERVED_MEMORY.get();
234         }
235     };
236 
237     // These numbers represent the point at which we have empirically
238     // determined that the average cost of a JNI call exceeds the expense
239     // of an element by element copy.  These numbers may change over time.
240     static final int JNI_COPY_TO_ARRAY_THRESHOLD   = 6;
241     static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6;
242     */
243     // END Android-removed: Direct memory management unused on Android.
244 }
245