View Javadoc
1   /*
2   * Copyright 2014 The Netty Project
3   *
4   * The Netty Project licenses this file to you under the Apache License,
5   * version 2.0 (the "License"); you may not use this file except in compliance
6   * with the License. You may obtain a copy of the License at:
7   *
8   *   http://www.apache.org/licenses/LICENSE-2.0
9   *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */
16  package io.netty.util.internal;
17  
18  import io.netty.util.internal.logging.InternalLogger;
19  import io.netty.util.internal.logging.InternalLoggerFactory;
20  
21  import java.lang.reflect.Field;
22  import java.lang.reflect.Method;
23  import java.nio.ByteBuffer;
24  
25  
26  /**
27   * Allows to free direct {@link ByteBuffer} by using Cleaner. This is encapsulated in an extra class to be able
28   * to use {@link PlatformDependent0} on Android without problems.
29   *
30   * For more details see <a href="https://github.com/netty/netty/issues/2604">#2604</a>.
31   */
32  final class CleanerJava6 implements Cleaner {
33      private static final long CLEANER_FIELD_OFFSET;
34      private static final Method CLEAN_METHOD;
35  
36      private static final InternalLogger logger = InternalLoggerFactory.getInstance(CleanerJava6.class);
37  
38      static {
39          long fieldOffset = -1;
40          Method clean = null;
41          Throwable error = null;
42          if (PlatformDependent0.hasUnsafe()) {
43              ByteBuffer direct = ByteBuffer.allocateDirect(1);
44              try {
45                  Field cleanerField = direct.getClass().getDeclaredField("cleaner");
46                  fieldOffset = PlatformDependent0.objectFieldOffset(cleanerField);
47                  Object cleaner = PlatformDependent0.getObject(direct, fieldOffset);
48                  clean = cleaner.getClass().getDeclaredMethod("clean");
49                  clean.invoke(cleaner);
50              } catch (Throwable t) {
51                  // We don't have ByteBuffer.cleaner().
52                  fieldOffset = -1;
53                  clean = null;
54                  error = t;
55              }
56          } else {
57              error = new UnsupportedOperationException("sun.misc.Unsafe unavailable");
58          }
59          if (error == null) {
60              logger.debug("java.nio.ByteBuffer.cleaner(): available");
61          } else {
62              logger.debug("java.nio.ByteBuffer.cleaner(): unavailable", error);
63          }
64          CLEANER_FIELD_OFFSET = fieldOffset;
65          CLEAN_METHOD = clean;
66      }
67  
68      static boolean isSupported() {
69          return CLEANER_FIELD_OFFSET != -1;
70      }
71  
72      @Override
73      public void freeDirectBuffer(ByteBuffer buffer) {
74          if (!buffer.isDirect()) {
75              return;
76          }
77          try {
78              Object cleaner = PlatformDependent0.getObject(buffer, CLEANER_FIELD_OFFSET);
79              if (cleaner != null) {
80                  CLEAN_METHOD.invoke(cleaner);
81              }
82          } catch (Throwable cause) {
83              PlatformDependent0.throwException(cause);
84          }
85      }
86  }