直接内存
1. 不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域
2. 直接内存是在Java堆外、直接向系统申请的内存区间
3. 来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存
4. 通常,访问直接内存的速度会优于Java堆,即读写性能高
5. 处于性能考虑,读写操作频繁的场合会考虑使用直接内存
6. Java的NIO库允许Java程序使用直接内存,用于数据缓冲区
7. 由于直接内存在Java堆外,因此它的大小不会直接受限于-Xmx指定的最大堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存。
8. 直接内存的大小可以通过MaxDirectMemorySize设置,如果不指定,则默认于堆的最大值-Xmx参数值一致
缺点:
分配回收成本较高
不受JVM内存回收管理
public class BufferTest {
private static final int BUFFER=1024*1024*1024;//1GB
public static void main(String[] args) {
// 直接分配内存空间
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
System.out.println("直接内存分配完毕,请求指示!");
Scanner scanner=new Scanner(System.in);
scanner.next();
System.out.println("直接内存开始释放");
byteBuffer =null;
System.gc();
scanner.next();
}
}
死锁
public class TestDeadLock implements Runnable {
public int flag = 1;
static Object o1 = new Object(), o2 = new Object();
public void run() {
System.out.println("flag=" + flag);
if (flag == 1) {
synchronized (o1) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (o2) {
System.out.println("1");
}
}
}
if (flag == 0) {
synchronized (o2) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (o1) {
System.out.println("0");
}
}
}
}
当flag为1时,线程首选获取o1锁,休眠500毫秒,然后尝试获取o2的锁,如果成功过,则打印"1".
当flag为2时,线程首选获取o2锁,休眠500毫秒,然后尝试获取o1的锁,如果成功过,则打印"0".
由于td1和flag为1,它首先获取了o1的锁,并休眠500毫秒。在td1休眠期间,td2开始执行并获取了o2的锁。当td1醒来兵尝试获取o2的锁时,它会被阻塞,因为o2的锁已经被td2持有,同样地,当td2醒来兵尝试获取o1的锁时,因为o1的锁已经被td1持有,这样,两个线程都陷入了等待状态,形成了死锁
为了避免死锁,可以采取以下策略:
方法句柄
静态方法句柄
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class MethodHandleExample {
public static void staticMethod(){
System.out.println("static method called");
}
public static void main(String[] args) throws Throwable {
// 获取当前类的查找器
MethodHandles.Lookup lookup=MethodHandles.lookup();
// 创建静态方法句柄
MethodHandle methodHandle=lookup.findStatic(MethodHandleExample.class,"staticMethod", MethodType.methodType(void.class));
// 调用方法句柄
methodHandle.invoke(); // static method called
}
}
实例方法句柄
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class MethodHandleExample {
public void instanceMethod() {
System.out.println("Instance method called");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException {
// 创建类的实例
MethodHandleExample example = new MethodHandleExample();
// 获取当前类的查找器
MethodHandles.Lookup lookup = MethodHandles.lookup();
// 创建实例方法句柄
MethodHandle methodHandle = lookup.findVirtual(MethodHandleExample.class, "instanceMethod", MethodType.methodType(void.class));
// 绑定实例并调用方法句柄
methodHandle.bindTo(example).invoke();
}
}
构造函数句柄
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class MethodHandleExample {
public MethodHandleExample() {
System.out.println("Constructor called");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException {
// 获取当前类的查找器
MethodHandles.Lookup lookup = MethodHandles.lookup();
// 创建构造函数句柄
MethodHandle constructorHandle = lookup.findConstructor(MethodHandleExample.class, MethodType.methodType(void.class));
// 调用构造函数句柄创建实例
MethodHandleExample example = (MethodHandleExample) constructorHandle.invoke();
}
}
方法句柄优势
方法句柄比传统的Java反射API更快,因为他们直接利用了JVM内部机制
方法句柄可以绑定到各种类型的方法上,包括私有方法和构造函数
方法句柄的访问控制更加细粒度,可以在运行时动态调整权限
public class Test {
class GrandFather{
void thinking(){
System.out.println("GrandFather ");
}
}
class Father extends GrandFather{
void thinking(){
System.out.println("Father");
}
}
class Son extends Father{
void thinking(){
try {
MethodType mt=MethodType.methodType(void.class);
// 获取当前类的查找器
MethodHandles.Lookup lookup=MethodHandles.lookup();
// 创建句柄
MethodHandle mh=lookup.findSpecial(GrandFather.class,"thinking",mt,getClass());
mh.invoke(this);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
(new Test().new Son()).thinking();
}
}
public class Test {
class GrandFather{
void thinking(){
System.out.println("GrandFather ");
}
}
class Father extends GrandFather{
void thinking(){
System.out.println("Father");
}
}
class Son extends Father{
void thinking(){
try {
MethodType mt=MethodType.methodType(void.class);
// 反射,绕过保护机制
Field lookupImpl =MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
lookupImpl.setAccessible(true);
// 获取当前类的查找器
// MethodHandles.Lookup lookup=MethodHandles.lookup();
// 创建句柄
MethodHandle mh=((MethodHandles.Lookup)lookupImpl.get(null)).findSpecial(GrandFather.class,"thinking",mt,GrandFather.class);
mh.invoke(this); //GrandFather
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
(new Test().new Son()).thinking();
}
}