Java中的JVM虚拟机的内存与直接内存

一. 定义

直接内存不属于java虚拟机内存,而属于操作系统内存

在这里插入图片描述

当我调用直接内存(Direct Memory)
在这里插入图片描述

  • Direct Memory
  1. 常见于 NIO 操作时,用于数据缓冲区
  2. 分配回收成本较高,但读写性能高
  3. 不受 JVM 内存回收管理

二. 直接内存的内存溢出

  • 演示图:
    在这里插入图片描述
  • 演示代码:
package jvm1;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

public class Demo9 {
    static int _100Mb = 1024 * 1024 * 100;

    public static void main(String[] args) {
        List<ByteBuffer> list = new ArrayList<>();//加入声明周期更长的List集合中
        int i = 0;
        try {
            while (true) {
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_100Mb);
                list.add(byteBuffer);
                i++;
            }
        } finally {
            System.out.println(i);
        }
        // 方法区是jvm规范, jdk6 中对方法区的实现称为永久代
        //                  jdk8 对方法区的实现称为元空间
    }
}

三. 直接内存的释放原理

案例1

  • 分析1
    在这里插入图片描述
  • 分析2
    在这里插入图片描述
  • 源码分析:
    在这里插入图片描述
  • 垃圾回收GC分析:

-XX:+DisableExplicitGC 禁用显式的垃圾回收

在这里插入图片描述

  • 原代码:
package jvm1;
import java.io.IOException;
import java.nio.ByteBuffer;

/*
  禁用显式回收对直接内存的影响
 */
public class Demo10 {
    static int _1Gb = 1024 * 1024 * 1024;

    /*
     * -XX:+DisableExplicitGC 显式的
     */
    public static void main(String[] args) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_1Gb);
        System.out.println("分配完毕...");
        System.in.read();//回车键
        System.out.println("开始释放...");
        byteBuffer = null;
        System.gc(); // 显式的垃圾回收,Full GC
        System.in.read();
    }
}

案例2

  • 分析1
    在这里插入图片描述
  • 原代码:
package jvm1;
import sun.misc.Unsafe;

import java.io.IOException;
import java.lang.reflect.Field;
/*
  直接内存分配的底层原理:Unsafe
 */
public class Demo11 {
    static int _1Gb = 1024 * 1024 * 1024;

    public static void main(String[] args) throws IOException {
        Unsafe unsafe = getUnsafe();
        // 分配内存
        long base = unsafe.allocateMemory(_1Gb);
        unsafe.setMemory(base, _1Gb, (byte) 0);
        System.in.read();

        // 释放内存
        unsafe.freeMemory(base);
        System.in.read();
    }

    public static Unsafe getUnsafe() {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe = (Unsafe) f.get(null);
            return unsafe;
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}

根据案例1和案例2的总结:

  • 分配和回收原理
    • 使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法
    • ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调用 freeMemory 来释放直接内存
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发热的嘤嘤怪(2003计科胜胜同学)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值