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  import sun.misc.Cleaner;
21  
22  import java.lang.reflect.Field;
23  import java.nio.ByteBuffer;
24  
25  
26  /**
27   * Allows to free direct {@link ByteBuffer} by using {@link 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 Cleaner0 {
33      private static final long CLEANER_FIELD_OFFSET;
34      private static final InternalLogger logger = InternalLoggerFactory.getInstance(Cleaner0.class);
35  
36      static {
37          ByteBuffer direct = ByteBuffer.allocateDirect(1);
38          Field cleanerField;
39          long fieldOffset = -1;
40          if (PlatformDependent0.hasUnsafe()) {
41              try {
42                  cleanerField = direct.getClass().getDeclaredField("cleaner");
43                  cleanerField.setAccessible(true);
44                  Cleaner cleaner = (Cleaner) cleanerField.get(direct);
45                  cleaner.clean();
46                  fieldOffset = PlatformDependent0.objectFieldOffset(cleanerField);
47              } catch (Throwable t) {
48                  // We don't have ByteBuffer.cleaner().
49                  fieldOffset = -1;
50              }
51          }
52          logger.debug("java.nio.ByteBuffer.cleaner(): {}", fieldOffset != -1? "available" : "unavailable");
53          CLEANER_FIELD_OFFSET = fieldOffset;
54  
55          // free buffer if possible
56          freeDirectBuffer(direct);
57      }
58  
59      static void freeDirectBuffer(ByteBuffer buffer) {
60          if (CLEANER_FIELD_OFFSET == -1 || !buffer.isDirect()) {
61              return;
62          }
63          try {
64              Cleaner cleaner = (Cleaner) PlatformDependent0.getObject(buffer, CLEANER_FIELD_OFFSET);
65              if (cleaner != null) {
66                  cleaner.clean();
67              }
68          } catch (Throwable t) {
69              // Nothing we can do here.
70          }
71      }
72  
73      private Cleaner0() { }
74  }