zoukankan      html  css  js  c++  java
  • Java堆外内存之突破JVM枷锁

    对于有Java开发经验的朋友都知道,Java中不需要手动的申请和释放内存,JVM会自动进行垃圾回收;而使用的内存是由JVM控制的。

    那么,什么时机会进行垃圾回收,如何避免过度频繁的垃圾回收?如果JVM给的内存不够用,怎么办?

    此时,堆外内存登场!利用堆外内存,不仅可以随意操控内存,还能提高网络交互的速度。

    背景1:JVM内存的分配

      对于JVM的内存规则,应该是老生常谈的东西了,这里我就简单的说下:

      新生代:一般来说新创建的对象都分配在这里。

      年老代:经过几次垃圾回收,新生代的对象就会放在年老代里面。年老代中的对象保存的时间更久。

      永久代:这里面存放的是class相关的信息,一般是不会进行垃圾回收的。

    背景2:JVM垃圾回收

      由于JVM会替我们执行垃圾回收,因此开发者根本不需要关心对象的释放。但是如果不了解其中的原委,很容易内存泄漏,只能两眼望天了!

      垃圾回收,大致可以分为下面几种:

      Minor GC:当新创建对象,内存空间不够的时候,就会执行这个垃圾回收。由于执行最频繁,因此一般采用复制回收机制。

      Major GC:清理年老代的内存,这里一般采用的是标记清除+标记整理机制。

      Full GC:有的说与Major GC差不多,有的说相当于执行minor+major回收,那么我们暂且可以认为Full GC就是全面的垃圾回收吧。

    堆外内存?

      堆外内存,其实就是不受JVM控制的内存。相比于堆内内存有几个优势:

      1 减少了垃圾回收的工作,因为垃圾回收会暂停其他的工作(可能使用多线程或者时间片的方式,根本感觉不到)

      2 加快了复制的速度。因为堆内在flush到远程时,会先复制到直接内存(非堆内存),然后在发送;而堆外内存相当于省略掉了这个工作。

      而福之祸所依,自然也有不好的一面:

      1 堆外内存难以控制,如果内存泄漏,那么很难排查

      2 堆外内存相对来说,不适合存储很复杂的对象。一般简单的对象或者扁平化的比较适合。

      

      堆外内存可以通过java.nio的ByteBuffer来创建,调用allocateDirect方法申请即可。参考API地址

      至于怎么用,读读API文档就知道啦~  

      另外,默认的情况下堆外内存是有一定的限制的,好像是64M吧....

      可以通过设置-XX:MaxDirectMemorySize=10M控制堆外内存的大小:

    堆外内存的垃圾回收

      堆外内存,既然可以无限使用,那么会不会用爆内存呢?这个是很有可能的...所以堆外内存的垃圾回收也很重要。

      由于堆外内存并不直接控制于JVM,因此只能等到full GC的时候才能垃圾回收!

      Full GC,一般发生在年老代垃圾回收以及调用System.gc的时候,这样肯定不能满足我们的需求!况且很多线上环境的JVM参数有-XX:+DisableExplicitGC,导致了System.gc()等于一个空函数,根本不会触发FGC,这一点在使用Netty框架时需要注意是否会出问题。

    于是度娘帮助解决了这个问题,网上有朋友十分聪明的利用内部实现接口,反向获取到了一个clear方法!

    复制代码
    package xing.test;
    
    import java.nio.ByteBuffer;
    import sun.nio.ch.DirectBuffer;
    
    public class NonHeapTest {
        public static void clean(final ByteBuffer byteBuffer) {  
            if (byteBuffer.isDirect()) {  
               ((DirectBuffer)byteBuffer).cleaner().clean();  
            }  
      }  
        
        public static void sleep(long i) {  
            try {  
                  Thread.sleep(i);  
             }catch(Exception e) {  
                  /*skip*/  
             }  
        }  
        public static void main(String []args) throws Exception {  
               ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024 * 200);  
               System.out.println("start");  
               sleep(5000);  
               clean(buffer);//执行垃圾回收
    //         System.gc();//执行Full gc进行垃圾回收
               System.out.println("end");  
               sleep(5000);  
        }  
    }
    复制代码

      这样就能手动的控制回收堆外内存了!其中sun.nio其实是java.nio的内部实现。所以你可能不能通过eclipse的自动排错找到这个包,直接复制

    import sun.nio.ch.DirectBuffer;

      就行。

      由于本文整理与网络各种资料,有些不对的地方还请指正,共同探讨!

  • 相关阅读:
    HOJ 2139 Spiderman's workout(动态规划)
    FZU 2107 Hua Rong Dao(dfs)
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
  • 原文地址:https://www.cnblogs.com/qiumingcheng/p/9487144.html
Copyright © 2011-2022 走看看