太阳娱乐集团官网-太阳集团2138手机版-欢迎您

▓太阳娱乐集团▓官网前与中国移动、中国电信、数百家音乐网站建立了紧密的合作关系,太阳集团2138手机版游戏为您提供百种在线娱乐:百家乐、老虎机电玩等娱乐游戏,欢迎您拥有最经典的玩法与手感,是金湖本地最权威最具人气的门户网站。

源码阅读,堆外内存整理
分类:太阳集团2138

DirectByteBuffer(int cap) { // package-private

// 先导化Buffer的多少个宗旨属性

super(-1, 0, cap, cap);

// 判定是还是不是需求页面前碰到齐,通过参数-XX:+PageAlignDirectMemory调节,默感到false

boolean pa = VM.isDirectMemoryPageAligned();

int ps = Bits.pageSize();

// 确认保障有丰富内部存款和储蓄器

long size = Math.max(1L, (long)cap + (pa ? ps : 0));

Bits.reserveMemory(size, cap);

long base = 0;

try {

// 调用unsafe方法分配内部存款和储蓄器

base = unsafe.allocateMemory(size);

} catch (OutOfMemoryError x) {

// 分配退步,释放内部存款和储蓄器

Bits.unreserveMemory(size, cap);

throw x;

}

// 开头化内部存款和储蓄器空间为0

unsafe.setMemory(base, size, (byte) 0);

// 设置内部存款和储蓄器初叶地址

if (pa && (base % ps != 0)) {

address = base + ps - (base & (ps - 1));

} else {

address = base;

}

// 使用Cleaner机制注册内部存款和储蓄器回笼管理函数

cleaner = Cleaner.create(this, new Deallocator(base, size, cap));

att = null;

}

堆外内部存款和储蓄器, JDK 1.4 nio引进了ByteBuffer.allocateDirect(卡塔尔(قطر‎分配堆外内部存储器

在GC的时候totalCapacity会被放走,看下具体得以完成。
在DirectByteBuffer中的内部类Deallocator:

public static ByteBuffer allocateDirect(int capacity) {

return new DirectByteBuffer(capacity);

}

  • ByteBuffer
    public static ByteBuffer allocateDirect(int capacity) {
    return new DirectByteBuffer(capacity);
    }

  • DirectByteBuffer
    DirectByteBuffer(int cap) {// package-private
    super(-1, 0, cap, cap);
    boolean pa = VM.isDirectMemoryPage阿里gned(卡塔尔(قطر‎;//内存是不是按页分配成对齐
    int ps = Bits.pageSize(卡塔尔;//获取每页内部存储器大小
    long size = Math.max(1L, (long卡塔尔cap + (pa ? ps : 0卡塔尔(قطر‎卡塔尔国;//分配内部存款和储蓄器的分寸,假使是按页对齐情势,供给再加风度翩翩页内部存款和储蓄器的体积
    主要:分配内部存款和储蓄器和自由内部存款和储蓄器以前必得调用此措施
    Bits.reserveMemory(size, cap卡塔尔(قطر‎;//用Bits类保存总分配内存(按页分配卡塔尔的深浅和骨子里内存的深浅
    long base = 0;
    try {//在堆外内部存储器的集散地址,内定内部存款和储蓄器大小
    base = unsafe.allocateMemory(sizeState of Qatar;//unsafe.cpp中调用os::malloc分配内部存款和储蓄器
    } catch (OutOfMemoryError x) {
    Bits.unreserveMemory(size, cap);
    throw x;
    }
    unsafe.setMemory(base, size, (byte) 0);
    if (pa && (base % ps != 0卡塔尔(قطر‎卡塔尔(قطر‎ {//总括堆外内部存款和储蓄器的集散地址
    // Round up to page boundary
    address = base + ps - (base & (ps - 1));
    } else {
    address = base;
    }
    cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
    att = null;
    }

  • Deallocator
    private static class Deallocator implements Runnable
    {
    private static Unsafe unsafe = Unsafe.getUnsafe();
    private long address;//基地址
    private long size;//保存了堆外内部存款和储蓄器的多寡(早先地址、大小和体积)
    private int capacity;//保存了堆外内部存款和储蓄器的数码(初阶地址、大小和体量)
    private Deallocator(long address, long size, int capacity) {
    assert (address != 0);
    this.address = address;
    this.size = size;
    this.capacity = capacity;
    }
    public void run() {
    if (address == 0) {
    // Paranoia
    return;
    }
    unsafe.freeMemory(address卡塔尔(قطر‎;//调用OS的法门释放地址,os::free
    address = 0;
    Bits.unreserveMemory(size, capacity卡塔尔;//计算堆外内部存款和储蓄器大小
    }
    }

  • Cleaner
    public class Cleaner extends PhantomReference<Object> {
    private static final ReferenceQueue<Object> dummyQueue = new ReferenceQueue();//static数据
    private static Cleaner first = null;//static数据
    private Cleaner next = null;
    private Cleaner prev = null;
    private final Runnable thunk;//Deallocator对象,每一种cleaner对象都保留了多少个Deallocator对象,它里面有address营地址等
    private static synchronized Cleaner add(Cleaner var0) {
    if(first != null) {
    var0.next = first;
    first.prev = var0;
    }
    first = var0;
    return var0;
    }
    private Cleaner(Object var1, Runnable var2) {
    super(var1, dummyQueue);//var1 传的是DirectByteBuffer对象
    this.thunk = var2;//Deallocator对象
    }
    public static Cleaner create(Object var0, Runnable var1) {
    return var1 == null?null:add(new Cleaner(var0, var1));//var0传的是DirectByteBuffer对象
    }

  • Bits
    // -- Direct memory management --
    // A user-settable upper limit on the maximum amount of allocatable direct buffer memory.
    // This value may be changed during VM initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
    private static volatile long maxMemory = VM.maxDirectMemory();
    private static volatile long reservedMemory;
    private static volatile long totalCapacity;
    private static volatile long count;
    private static boolean memoryLimitSet = false;
    // These methods should be called whenever direct memory is allocated or
    // freed. They allow the user to control the amount of direct memory
    // which a process may access. All sizes are specified in bytes.
    static void reserveMemory(long size, int cap) {
    synchronized (Bits.class) {
    太阳亚洲sun988con,if (!memoryLimitSet && VM.isBooted()) {
    maxMemory = VM.maxDirectMemory();// 67108864L == 64MB
    memoryLimitSet = true;
    }
    // -XX:MaxDirectMemorySize limits the total capacity rather than the
    // actual memory usage, which will differ when buffers are page aligned.
    if (cap <= maxMemory - totalCapacity) {
    reservedMemory += size;
    totalCapacity += cap;
    count++;
    return;
    }
    }
    System.gc(卡塔尔国;//内部存款和储蓄器非常不够了, try gc
    try {
    Thread.sleep(100);
    } catch (InterruptedException x) {
    // Restore interrupt status
    Thread.currentThread().interrupt();
    }
    synchronized (Bits.class) {
    if (totalCapacity + cap > maxMemory)
    throw new OutOfMemoryError("Direct buffer memory");
    reservedMemory += size;
    totalCapacity += cap;
    count++;
    }
    }
    static synchronized void unreserveMemory(long size, int cap) {
    if (reservedMemory > 0) {
    reservedMemory -= size;
    totalCapacity -= cap;
    count--;
    assert (reservedMemory > -1);
    }
    }

  • 太阳集团娱乐网址09055,DirectByteBuffer被回收

    DirectByteBuffer对象在创建的时候关系了三个PhantomReference,聊到PhantomReference它事实上根本是用来跟踪对象哪一天被回笼的,
    它不可能影响gc决策,但是gc过程中如若发掘某些对象除了独有PhantomReference援用它之外,并未此外的地点援引它了,
    那将会把那些援引(Cleaner)放到java.lang.ref.Reference.pending队列里,
    在gc完结的时候布告ReferenceHandler那几个守护线程去实施一些前置管理,
    而DirectByteBuffer关联的PhantomReference是PhantomReference的多少个子类,
    在最后的拍卖里会通过Unsafe的free接口来刑满释放解除劳教DirectByteBuffer对应的堆外内部存储器块

  • JDK里面的ReferenceHandler实现
    private static class ReferenceHandler extends Thread {
    ReferenceHandler(ThreadGroup g, String name) {
    super(g, name);
    }
    public void run() {
    for (;;) {
    Reference r;
    synchronized (lock) {
    if (pending != null) {
    r = pending;
    Reference rn = r.next;
    pending = (rn == r) ? null : rn;
    r.next = r;
    } else {
    try {
    lock.wait();
    } catch (InterruptedException x) { }
    continue;
    }
    }
    // Fast path for cleaners
    if (r instanceof Cleaner) {
    ((Cleaner卡塔尔r卡塔尔(قطر‎.clean(卡塔尔;//直接调用clean方法清理
    continue;
    }
    ReferenceQueue q = r.queue;
    if (q != ReferenceQueue.NULL) q.enqueue(r);
    }
    }
    }

  • 简言之流程梳理

    • 堆外内部存款和储蓄器的报名
      • ByteBuffer.allocateDirect()
      • unsafe.allocateMemory()
      • os::malloc()
    • 堆外内部存款和储蓄器的假释
      • cleaner.clean()
        • 把笔者从Clener链表删除,进而在下一次GC时可以被回笼
        • 放活堆外内部存款和储蓄器
      • unsafe.freeMemory()
      • os::free()
  • 对象的援引关系

    • 太阳亚洲sun988con 1

      初始化时

    • 太阳亚洲sun988con 2

      假定该DirectByteBuffer对象在一次GC中被回笼了

  • 不过比非常多线上蒙受的JVM参数有-XX:+DisableExplicitGC,引致了System.gc(卡塔尔等于四个空函数,根本不会触发FGC,那一点在运用Netty框架时须要注意是还是不是会出难题

  • 至于直接内部存款和储蓄器私下认可值是还是不是为64MB?

    • java.lang.System
      private static void initializeSystemClass() {//Initialize the system class. Called after thread initialization.
      ...
      sun.misc.VM.saveAndRemoveProperties(props);
      ...
      }
    • saveAndRemoveProperties(){
      // Set the maximum amount of direct memory. This value is controlled
      // by the vm option -XX:MaxDirectMemorySize=<size>.
      // The maximum amount of allocatable direct buffer memory (in bytes)
      // from the system property sun.nio.MaxDirectMemorySize set by the VM.
      // The system property will be removed.
      String s = (String)props.remove("sun.nio.MaxDirectMemorySize");
      if (s != null) {
      if (s.equals("-1")) {
      // -XX:MaxDirectMemorySize not given, take default
      directMemory = Runtime.getRuntime().maxMemory();
      } else {
      long l = Long.parseLong(s);
      if (l > -1)
      directMemory = l;
      }
      }}
    • 假定大家经过-Dsun.nio.MaxDirectMemorySize钦定了这些性子,只要它不对等-1,那效果和加了-XX:MaxDirectMemorySize形似的,如若八个参数都没钦定,那么最大堆外内部存款和储蓄器的值来自于directMemory = Runtime.getRuntime(卡塔尔.maxMemory(卡塔尔(قطر‎,那是贰个native方法
    • Universe::heap()->max_capacity();
    • 里头在大家使用CMS GC的事态下的完毕如下,其实是新生代的最大值-多少个surSamsungr的深浅+老生代的最大值,也等于大家设置的-Xmx的值里除了叁个surSamsungr的轻重正是暗中同意的堆外内部存款和储蓄器的高低了
  • 假若开采有个别对象除了只有PhantomReference援用它之外,并从未其余的地点援用它了,那将会把那么些援引放到java.lang.ref.Reference.pending队列里,在gc实现的时候公告ReferenceHandler这一个守护线程去施行一些前置管理

  • 足见假设pending为空的时候,会因此lock.wait(卡塔尔一贯等在那里,当中唤醒的动作是在jvm里做的,当gc达成之后会调用如下的章程VM_GC_Operation::doit_epilogue(卡塔尔,在艺术末尾会调用lock的notify操作,至于pending队列何时将援引放进去的,其实是在gc的引用途理逻辑中放进去的,针对引用的管理前面能够特意写篇小说来介绍

  • 对此System.gc的完成,它会对新生代和老生代都会进行内部存款和储蓄器回笼,那样会比较根本地回笼DirectByteBuffer对象甚至他们关系的堆外内部存款和储蓄器,我们dump内部存款和储蓄器开掘DirectByteBuffer对象自己其实是极小的,可是它背后大概涉及了叁个要命大的堆外内部存储器,因而我们常常称为『冰山目的』,大家做ygc的时候会将新生代里的不可达的DirectByteBuffer对象及其堆外内部存款和储蓄器回笼了,但是心有余而力不足对old里的DirectByteBuffer对象及其堆外内部存款和储蓄器实行回收,那也是大家多如牛毛遭遇的最大的主题材料,借使有恢宏的DirectByteBuffer对象移到了old,不过又间接未曾做cms gc也许full gc,而只举办ygc,那么大家的情理内存恐怕被渐渐耗光,不过我们还不知情产生了如何,因为heap明明剩余的内部存款和储蓄器还超级多(前提是大家禁止使用了System.gc卡塔尔。

  • 作者们通讯进程中只要数额是在Heap里的,最后也依旧会copy大器晚成份到堆外,然后再开展发送,所以怎么不直接行使堆外内部存款和储蓄器呢

  • gc机制与堆外内部存款和储蓄器的关系也说了,假设直接触发不了cms gc可能full gc,那么结果大概好惨痛

  • References

    • 笨神-JVM源码深入分析之堆外内存完全解读
    • 占小狼-堆外内部存款和储蓄器的回笼机制深入分析
    • 从0到1起步-跟自家进来堆外内部存款和储蓄器的奇异世界

DirectByteBuffer回笼流程

//减少使用内存总量的计数器
static synchronized void unreserveMemory(long size, int cap) {
        if (reservedMemory > 0) {
            reservedMemory -= size;
            totalCapacity -= cap;
            count--;
            assert (reservedMemory > -1);
        }
}

假使要求实例化多个DirectByteBuffer,能够利用java.nio.ByteBuffer#allocateDirect这几个措施:

Deallocator在DirectByteBuffer的结构函数中:

  • Java Max Direct Memory Size设置 – CSDN博客
  • Runtime.getRunTime.maxMemory为什么比Xmx钦点的内部存款和储蓄器小 – CSDN博客
  • JVM源码解析之堆外内部存款和储蓄器完全解读 – 你假笨
DirectByteBuffer(int cap) {                   // package-private

        super(-1, 0, cap, cap);
        boolean pa = VM.isDirectMemoryPageAligned();
        int ps = Bits.pageSize();
        long size = Math.max(1L, (long)cap + (pa ? ps : 0));
        Bits.reserveMemory(size, cap);

        long base = 0;
        try {
            base = unsafe.allocateMemory(size);
        } catch (OutOfMemoryError x) {
            Bits.unreserveMemory(size, cap);
            throw x;
        }
        unsafe.setMemory(base, size, (byte) 0);
        if (pa && (base % ps != 0)) {
            // Round up to page boundary
            address = base + ps - (base & (ps - 1));
        } else {
            address = base;
        }
        cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
        att = null;
    }

Java中可选的性状有finalize函数,可是finalize机制是Java官方不引入的,官方推荐的做法是应用虚引用来拍卖对象被回笼时的持续处总管业,能够参见JDK源码阅读-Reference。同有时候Java提供了Cleaner类来简化这一个达成,Cleaner是PhantomReference的子类,能够在PhantomReference被投入ReferenceQueue时触发对应的Runnable回调。

重在代码:

DirectByteBuffer读写逻辑

...省略
public void run() {
    if (address == 0) {
                // Paranoia
                return;
    }
    unsafe.freeMemory(address);//释放内存
    address = 0;
    Bits.unreserveMemory(size, capacity);//回收totalCapacity
}
...省略

style="font-size: 16px;">

java.nio.Bits:

sun.misc.Unsafe#freeMemory方法应用C规范库的free函数释放内部存款和储蓄器空间。同期更新Bits类中的总计变量。

找到DirectByteBuffer的布局函数

DirectByteBuffer通过sun.misc.VM#maxDirectMemory来收获这几个值,能够看一下应和的代码:

大家来稳重看下Cleaner对象:

主编:

...省略部分代码
public class Cleaner extends PhantomReference<Object> {
  public static Cleaner create(Object var0, Runnable var1) {
    return var1 == null?null:add(new Cleaner(var0, var1));
  }

  private static synchronized Cleaner add(Cleaner var0) {
    if(first != null) {
      var0.next = first;
      first.prev = var0;
    }

    first = var0;
    return var0;
  }  

 public void clean() {
        if(remove(this)) {
            try {
                this.thunk.run();
            } catch (final Throwable var2) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        if(System.err != null) {
                            (new Error("Cleaner terminated abnormally", var2)).printStackTrace();
                        }

                        System.exit(1);
                        return null;
                    }
                });
            }

        }
    }
}

就此最终敲定是:暗许景况下,可以报名的最大DirectByteBuffer空间为Java最大堆大小的值。

Cleaner世襲了虚援引,何况个中是二个双向链表,每一趟create时加多到表头。
虚援引简易来说正是在GC时,将目的放入ReferenceQueue中,具体的能够寻觅相关知识,再看实行Deallocator线程的clean函数,找到调用之处:

大家来看一下DirectByteBuffer是何许组织,怎么样申请与释放内部存款和储蓄器的。先看看DirectByteBuffer的构造函数:

  • Bits.reserveMemory(size, cap卡塔尔国;检验是不是丰裕分配空间,并增添之中总的数量流速計
  • unsafe.allocateMemory(sizeState of Qatar; 通过Unsafe类分配内部存款和储蓄器地址
  • cleaner = Cleaner.create(this, new Deallocator(base, size, cap卡塔尔(قطر‎卡塔尔;创设清理类,用于内部存储器回笼
    java.nio.Bits

上文提到了DirectByteBuffer申请内部存储器前会咬定是不是有丰裕的长空可供申请,这么些是在二个钦定的堆外大小节制的前提下。客户能够透过-XX:MaxDirectMemorySize=<size>那么些参数来调节能够报名多大的DirectByteBuffer内部存款和储蓄器。不过暗许意况下那一个分寸是微微呢?

ReferenceHandler是全局的护理线程,用于将虚援引的对象增加到ReferenceQueue中
会见在ReferenceHandler中enqueue前,会先检验Cleaner对象,而且这里continue了,也正是说Cleaner对象不会像平日的虚援用雷同放入ReferenceQueue中。
据此能够知晓为Cleaner使用虚引用为的是使用ReferenceHandler线程在gc时释放堆外内部存款和储蓄器。

暗许能够申请的堆外内部存储器大小

// These methods should be called whenever direct memory is allocated or  
    // freed.  They allow the user to control the amount of direct memory  
    // which a process may access.  All sizes are specified in bytes.  
    static void reserveMemory(long size, int cap) {  
        //因为内存分配是全局的,所以必须加锁
        synchronized (Bits.class) {  
            if (!memoryLimitSet && VM.isBooted()) {  
                maxMemory = VM.maxDirectMemory();  //最大堆外内存设置
                memoryLimitSet = true;  
            }  
            // -XX:MaxDirectMemorySize limits the total capacity rather than the  
            // actual memory usage, which will differ when buffers are page  
            // aligned.  
            //如果剩余空间足够,增加总量计数器直接返回
            if (cap <= maxMemory - totalCapacity) { 
                reservedMemory += size;  
                totalCapacity += cap;  
                count++;  
                return;  
            }  
        }  

        //如果剩余空间不足,那么先执行一次GC
        System.gc();  
        try {  
            Thread.sleep(100);//其实jvm也用了很low的sleep下,等待GC完成
        } catch (InterruptedException x) {  
            // Restore interrupt status  
            Thread.currentThread().interrupt();  
        }  
        //这里同样,在计算的时候必须是同步的
        synchronized (Bits.class) {  
            //如果内存空间还是不够,则抛出异常
            if (totalCapacity + cap > maxMemory)
                throw new OutOfMemoryError("Direct buffer memory");  
            reservedMemory += size;  
            totalCapacity += cap;  
            count++;  
        }  

    } 

public ByteBuffer put(int i, byte x) {

unsafe.putByte(ix(checkIndex(i)), ((x)));

return this;

}

public byte get(int i) {

return ((unsafe.getByte(ix(checkIndex(i)))));

}

private long ix(int i) {

return address + (i << 0);

}

DirectByteBuffer(int cap) {                   // package-private
      ...省略
      cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
      ...省略
}

原标题:JDK 源码阅读 : DirectByteBuffer

最近在查二个堆外内部存款和储蓄器走漏的难点,顺便学习了下MaxDirectMemorySize使用。
总所周知-XX:MaxDirectMemorySize能够设置java堆外内存的峰值,但是现实是在哪个地方节制的啊,来追踪下创制DirectByteBuffer的历程。

本文由太阳娱乐集团官网发布于太阳集团2138,转载请注明出处:源码阅读,堆外内存整理

上一篇:交行四川省分行扎实开展峨边扶贫攻坚,抓好关 下一篇:没有了
猜你喜欢
热门排行
精彩图文