|
18 | 18 | import java.io.File; |
19 | 19 | import java.io.IOException; |
20 | 20 | import java.io.InputStream; |
21 | | -import java.lang.reflect.Field; |
22 | | -import java.lang.reflect.Method; |
23 | 21 | import java.nio.ByteBuffer; |
24 | 22 | import java.nio.channels.FileChannel; |
25 | 23 | import java.nio.file.Path; |
|
40 | 38 | * |
41 | 39 | * @since 2.9.0 |
42 | 40 | */ |
43 | | -@SuppressWarnings("restriction") |
44 | 41 | public final class BufferedFileChannelInputStream extends InputStream { |
45 | 42 |
|
46 | 43 | private final ByteBuffer byteBuffer; |
47 | 44 |
|
48 | 45 | private final FileChannel fileChannel; |
49 | 46 |
|
50 | | - private static final Class<?> DIRECT_BUFFER_CLASS = getDirectBufferClass(); |
51 | | - |
52 | | - private static Class<?> getDirectBufferClass() { |
53 | | - Class<?> res = null; |
54 | | - try { |
55 | | - res = Class.forName("sun.nio.ch.DirectBuffer"); |
56 | | - } catch (final IllegalAccessError | ClassNotFoundException ignored) { |
57 | | - // ignored |
58 | | - } |
59 | | - return res; |
60 | | - } |
61 | | - |
62 | | - private static boolean isDirectBuffer(final Object object) { |
63 | | - return DIRECT_BUFFER_CLASS != null && DIRECT_BUFFER_CLASS.isInstance(object); |
64 | | - } |
65 | | - |
66 | 47 | /** |
67 | 48 | * Constructs a new instance for the given File. |
68 | 49 | * |
@@ -115,75 +96,30 @@ public synchronized int available() throws IOException { |
115 | 96 |
|
116 | 97 | /** |
117 | 98 | * Attempts to clean up a ByteBuffer if it is direct or memory-mapped. This uses an *unsafe* Sun API that will cause |
118 | | - * errors if one attempts to read from the disposed buffer. However, neither the bytes allocated to direct buffers |
119 | | - * nor file descriptors opened for memory-mapped buffers put pressure on the garbage collector. Waiting for garbage |
| 99 | + * errors if one attempts to read from the disposed buffer. However, neither the bytes allocated to direct buffers nor |
| 100 | + * file descriptors opened for memory-mapped buffers put pressure on the garbage collector. Waiting for garbage |
120 | 101 | * collection may lead to the depletion of off-heap memory or huge numbers of open files. There's unfortunately no |
121 | 102 | * standard API to manually dispose of these kinds of buffers. |
122 | 103 | * |
123 | 104 | * @param buffer the buffer to clean. |
124 | 105 | */ |
125 | 106 | private void clean(final ByteBuffer buffer) { |
126 | | - if (isDirectBuffer(buffer)) { |
| 107 | + if (buffer.isDirect()) { |
127 | 108 | cleanDirectBuffer(buffer); |
128 | 109 | } |
129 | 110 | } |
130 | 111 |
|
131 | 112 | /** |
132 | | - * In Java 8, the type of DirectBuffer.cleaner() was sun.misc.Cleaner, and it was possible to access the method |
133 | | - * sun.misc.Cleaner.clean() to invoke it. The type changed to jdk.internal.ref.Cleaner in later JDKs, and the |
134 | | - * .clean() method is not accessible even with reflection. However sun.misc.Unsafe added a invokeCleaner() method in |
135 | | - * JDK 9+ and this is still accessible with reflection. |
| 113 | + * In Java 8, the type of {@code sun.nio.ch.DirectBuffer.cleaner()} was {@code sun.misc.Cleaner}, and it was possible to |
| 114 | + * access the method {@code sun.misc.Cleaner.clean()} to invoke it. The type changed to {@code jdk.internal.ref.Cleaner} |
| 115 | + * in later JDKs, and the {@code clean()} method is not accessible even with reflection. However {@code sun.misc.Unsafe} |
| 116 | + * added an {@code invokeCleaner()} method in JDK 9+ and this is still accessible with reflection. |
136 | 117 | * |
137 | 118 | * @param buffer the buffer to clean. must be a DirectBuffer. |
138 | 119 | */ |
139 | 120 | private void cleanDirectBuffer(final ByteBuffer buffer) { |
140 | | - // |
141 | | - // Ported from StorageUtils.scala. |
142 | | - // |
143 | | -// private val bufferCleaner: DirectBuffer => Unit = |
144 | | -// if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9)) { |
145 | | -// val cleanerMethod = |
146 | | -// Utils.classForName("sun.misc.Unsafe").getMethod("invokeCleaner", classOf[ByteBuffer]) |
147 | | -// val unsafeField = classOf[Unsafe].getDeclaredField("theUnsafe") |
148 | | -// unsafeField.setAccessible(true) |
149 | | -// val unsafe = unsafeField.get(null).asInstanceOf[Unsafe] |
150 | | -// buffer: DirectBuffer => cleanerMethod.invoke(unsafe, buffer) |
151 | | -// } else { |
152 | | -// val cleanerMethod = Utils.classForName("sun.misc.Cleaner").getMethod("clean") |
153 | | -// buffer: DirectBuffer => { |
154 | | -// // Careful to avoid the return type of .cleaner(), which changes with JDK |
155 | | -// val cleaner: AnyRef = buffer.cleaner() |
156 | | -// if (cleaner != null) { |
157 | | -// cleanerMethod.invoke(cleaner) |
158 | | -// } |
159 | | -// } |
160 | | -// } |
161 | | - // |
162 | | - final String specVer = System.getProperty("java.specification.version"); |
163 | | - if ("1.8".equals(specVer)) { |
164 | | - // On Java 8, but also compiles on Java 11. |
165 | | - try { |
166 | | - final Class<?> clsCleaner = Class.forName("sun.misc.Cleaner"); |
167 | | - final Method cleanerMethod = DIRECT_BUFFER_CLASS.getMethod("cleaner"); |
168 | | - final Object cleaner = cleanerMethod.invoke(buffer); |
169 | | - if (cleaner != null) { |
170 | | - final Method cleanMethod = clsCleaner.getMethod("clean"); |
171 | | - cleanMethod.invoke(cleaner); |
172 | | - } |
173 | | - } catch (final ReflectiveOperationException e) { |
174 | | - throw new IllegalStateException(e); |
175 | | - } |
176 | | - } else { |
177 | | - // On Java 9 and up, but compiles on Java 8. |
178 | | - try { |
179 | | - final Class<?> clsUnsafe = Class.forName("sun.misc.Unsafe"); |
180 | | - final Method cleanerMethod = clsUnsafe.getMethod("invokeCleaner", ByteBuffer.class); |
181 | | - final Field unsafeField = clsUnsafe.getDeclaredField("theUnsafe"); |
182 | | - unsafeField.setAccessible(true); |
183 | | - cleanerMethod.invoke(unsafeField.get(null), buffer); |
184 | | - } catch (final ReflectiveOperationException e) { |
185 | | - throw new IllegalStateException(e); |
186 | | - } |
| 121 | + if (ByteBufferCleaner.isSupported()) { |
| 122 | + ByteBufferCleaner.clean(buffer); |
187 | 123 | } |
188 | 124 | } |
189 | 125 |
|
|
0 commit comments