001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.util; 019 020import java.lang.management.ManagementFactory; 021import java.lang.reflect.InvocationTargetException; 022import java.lang.reflect.Method; 023import java.nio.ByteBuffer; 024import javax.management.JMException; 025import javax.management.MBeanServer; 026import javax.management.MalformedObjectNameException; 027import javax.management.ObjectName; 028import org.apache.yetus.audience.InterfaceAudience; 029import org.apache.yetus.audience.InterfaceStability; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 034import org.apache.hbase.thirdparty.io.netty.buffer.ByteBufAllocatorMetric; 035import org.apache.hbase.thirdparty.io.netty.buffer.ByteBufAllocatorMetricProvider; 036import org.apache.hbase.thirdparty.io.netty.buffer.PooledByteBufAllocator; 037import org.apache.hbase.thirdparty.io.netty.util.internal.PlatformDependent; 038 039/** 040 * Utilities for interacting with and monitoring DirectByteBuffer allocations. 041 */ 042@InterfaceAudience.Private 043@InterfaceStability.Evolving 044public class DirectMemoryUtils { 045 private static final Logger LOG = LoggerFactory.getLogger(DirectMemoryUtils.class); 046 private static final String MEMORY_USED = "MemoryUsed"; 047 private static final MBeanServer BEAN_SERVER; 048 private static final ObjectName NIO_DIRECT_POOL; 049 private static final boolean HAS_MEMORY_USED_ATTRIBUTE; 050 private static final long MAX_DIRECT_MEMORY = PlatformDependent.estimateMaxDirectMemory(); 051 052 static { 053 // initialize singletons. Only maintain a reference to the MBeanServer if 054 // we're able to consume it -- hence convoluted logic. 055 ObjectName n = null; 056 MBeanServer s = null; 057 Object a = null; 058 try { 059 n = new ObjectName("java.nio:type=BufferPool,name=direct"); 060 } catch (MalformedObjectNameException e) { 061 LOG.warn("Unable to initialize ObjectName for DirectByteBuffer allocations."); 062 } finally { 063 NIO_DIRECT_POOL = n; 064 } 065 if (NIO_DIRECT_POOL != null) { 066 s = ManagementFactory.getPlatformMBeanServer(); 067 } 068 BEAN_SERVER = s; 069 if (BEAN_SERVER != null) { 070 try { 071 a = BEAN_SERVER.getAttribute(NIO_DIRECT_POOL, MEMORY_USED); 072 } catch (JMException e) { 073 LOG.debug("Failed to retrieve nio.BufferPool direct MemoryUsed attribute: " + e); 074 } 075 } 076 HAS_MEMORY_USED_ATTRIBUTE = a != null; 077 } 078 079 /** Returns the direct memory limit of the current progress */ 080 public static long getDirectMemorySize() { 081 return MAX_DIRECT_MEMORY; 082 } 083 084 /** Returns the current amount of direct memory used. */ 085 public static long getDirectMemoryUsage() { 086 if (BEAN_SERVER == null || NIO_DIRECT_POOL == null || !HAS_MEMORY_USED_ATTRIBUTE) return 0; 087 try { 088 Long value = (Long) BEAN_SERVER.getAttribute(NIO_DIRECT_POOL, MEMORY_USED); 089 return value == null ? 0 : value; 090 } catch (JMException e) { 091 // should print further diagnostic information? 092 return 0; 093 } 094 } 095 096 /** Returns the current amount of direct memory used by netty module. */ 097 public static long getNettyDirectMemoryUsage() { 098 099 ByteBufAllocatorMetric metric = 100 ((ByteBufAllocatorMetricProvider) PooledByteBufAllocator.DEFAULT).metric(); 101 return metric.usedDirectMemory(); 102 } 103 104 /** 105 * DirectByteBuffers are garbage collected by using a phantom reference and a reference queue. 106 * Every once a while, the JVM checks the reference queue and cleans the DirectByteBuffers. 107 * However, as this doesn't happen immediately after discarding all references to a 108 * DirectByteBuffer, it's easy to OutOfMemoryError yourself using DirectByteBuffers. This function 109 * explicitly calls the Cleaner method of a DirectByteBuffer. The DirectByteBuffer that will be 110 * "cleaned". Utilizes reflection. 111 */ 112 public static void destroyDirectByteBuffer(ByteBuffer toBeDestroyed) 113 throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, 114 SecurityException, NoSuchMethodException { 115 116 Preconditions.checkArgument(toBeDestroyed.isDirect(), "toBeDestroyed isn't direct!"); 117 118 Method cleanerMethod = toBeDestroyed.getClass().getMethod("cleaner"); 119 cleanerMethod.setAccessible(true); 120 Object cleaner = cleanerMethod.invoke(toBeDestroyed); 121 Method cleanMethod = cleaner.getClass().getMethod("clean"); 122 cleanMethod.setAccessible(true); 123 cleanMethod.invoke(cleaner); 124 } 125}