1 /*
2  * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */

25
26 package java.nio;
27
28 import jdk.internal.misc.JavaLangRefAccess;
29 import jdk.internal.misc.JavaNioAccess;
30 import jdk.internal.misc.SharedSecrets;
31 import jdk.internal.misc.Unsafe;
32 import jdk.internal.misc.VM;
33
34 import java.util.concurrent.atomic.AtomicLong;
35
36 /**
37  * Access to bits, native and otherwise.
38  */

39
40 class Bits {                            // package-private
41
42     private Bits() { }
43
44
45     // -- Swapping --
46
47     static short swap(short x) {
48         return Short.reverseBytes(x);
49     }
50
51     static char swap(char x) {
52         return Character.reverseBytes(x);
53     }
54
55     static int swap(int x) {
56         return Integer.reverseBytes(x);
57     }
58
59     static long swap(long x) {
60         return Long.reverseBytes(x);
61     }
62
63
64     // -- Unsafe access --
65
66     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
67
68     // -- Processor and memory-system properties --
69
70     private static int PAGE_SIZE = -1;
71
72     static int pageSize() {
73         if (PAGE_SIZE == -1)
74             PAGE_SIZE = UNSAFE.pageSize();
75         return PAGE_SIZE;
76     }
77
78     static int pageCount(long size) {
79         return (int)(size + (long)pageSize() - 1L) / pageSize();
80     }
81
82     private static boolean UNALIGNED = UNSAFE.unalignedAccess();
83
84     static boolean unaligned() {
85         return UNALIGNED;
86     }
87
88
89     // -- Direct memory management --
90
91     // A user-settable upper limit on the maximum amount of allocatable
92     // direct buffer memory.  This value may be changed during VM
93     // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
94     private static volatile long MAX_MEMORY = VM.maxDirectMemory();
95     private static final AtomicLong RESERVED_MEMORY = new AtomicLong();
96     private static final AtomicLong TOTAL_CAPACITY = new AtomicLong();
97     private static final AtomicLong COUNT = new AtomicLong();
98     private static volatile boolean MEMORY_LIMIT_SET;
99
100     // max. number of sleeps during try-reserving with exponentially
101     // increasing delay before throwing OutOfMemoryError:
102     // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
103     // which means that OOME will be thrown after 0.5 s of trying
104     private static final int MAX_SLEEPS = 9;
105
106     // These methods should be called whenever direct memory is allocated or
107     // freed.  They allow the user to control the amount of direct memory
108     // which a process may access.  All sizes are specified in bytes.
109     static void reserveMemory(long size, int cap) {
110
111         if (!MEMORY_LIMIT_SET && VM.initLevel() >= 1) {
112             MAX_MEMORY = VM.maxDirectMemory();
113             MEMORY_LIMIT_SET = true;
114         }
115
116         // optimist!
117         if (tryReserveMemory(size, cap)) {
118             return;
119         }
120
121         final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
122         boolean interrupted = false;
123         try {
124
125             // Retry allocation until success or there are no more
126             // references (including Cleaners that might free direct
127             // buffer memory) to process and allocation still fails.
128             boolean refprocActive;
129             do {
130                 try {
131                     refprocActive = jlra.waitForReferenceProcessing();
132                 } catch (InterruptedException e) {
133                     // Defer interrupts and keep trying.
134                     interrupted = true;
135                     refprocActive = true;
136                 }
137                 if (tryReserveMemory(size, cap)) {
138                     return;
139                 }
140             } while (refprocActive);
141
142             // trigger VM's Reference processing
143             System.gc();
144
145             // A retry loop with exponential back-off delays.
146             // Sometimes it would suffice to give up once reference
147             // processing is complete.  But if there are many threads
148             // competing for memory, this gives more opportunities for
149             // any given thread to make progress.  In particular, this
150             // seems to be enough for a stress test like
151             // DirectBufferAllocTest to (usually) succeed, while
152             // without it that test likely fails.  Since failure here
153             // ends in OOME, there's no need to hurry.
154             long sleepTime = 1;
155             int sleeps = 0;
156             while (true) {
157                 if (tryReserveMemory(size, cap)) {
158                     return;
159                 }
160                 if (sleeps >= MAX_SLEEPS) {
161                     break;
162                 }
163                 try {
164                     if (!jlra.waitForReferenceProcessing()) {
165                         Thread.sleep(sleepTime);
166                         sleepTime <<= 1;
167                         sleeps++;
168                     }
169                 } catch (InterruptedException e) {
170                     interrupted = true;
171                 }
172             }
173
174             // no luck
175             throw new OutOfMemoryError("Direct buffer memory");
176
177         } finally {
178             if (interrupted) {
179                 // don't swallow interrupts
180                 Thread.currentThread().interrupt();
181             }
182         }
183     }
184
185     private static boolean tryReserveMemory(long size, int cap) {
186
187         // -XX:MaxDirectMemorySize limits the total capacity rather than the
188         // actual memory usage, which will differ when buffers are page
189         // aligned.
190         long totalCap;
191         while (cap <= MAX_MEMORY - (totalCap = TOTAL_CAPACITY.get())) {
192             if (TOTAL_CAPACITY.compareAndSet(totalCap, totalCap + cap)) {
193                 RESERVED_MEMORY.addAndGet(size);
194                 COUNT.incrementAndGet();
195                 return true;
196             }
197         }
198
199         return false;
200     }
201
202
203     static void unreserveMemory(long size, int cap) {
204         long cnt = COUNT.decrementAndGet();
205         long reservedMem = RESERVED_MEMORY.addAndGet(-size);
206         long totalCap = TOTAL_CAPACITY.addAndGet(-cap);
207         assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
208     }
209
210     static final JavaNioAccess.BufferPool BUFFER_POOL = new JavaNioAccess.BufferPool() {
211         @Override
212         public String getName() {
213             return "direct";
214         }
215         @Override
216         public long getCount() {
217             return Bits.COUNT.get();
218         }
219         @Override
220         public long getTotalCapacity() {
221             return Bits.TOTAL_CAPACITY.get();
222         }
223         @Override
224         public long getMemoryUsed() {
225             return Bits.RESERVED_MEMORY.get();
226         }
227     };
228
229     // These numbers represent the point at which we have empirically
230     // determined that the average cost of a JNI call exceeds the expense
231     // of an element by element copy.  These numbers may change over time.
232     static final int JNI_COPY_TO_ARRAY_THRESHOLD   = 6;
233     static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6;
234 }
235