OOM以及垃圾收集器

点点圈 提交于 2020-02-26 10:06:15

1.常见的几种OOM?

①java.lang.StackOverflowError②java.lang.OutOfMemoryError:Java heap space③java.lang.OutOfMemoryError:GC overhead limit exceeded④java.lang.OutOfMemoryError:Direct buffer memory⑤java.lang.OutOfMemoryError:unable to create new native thread⑥java.lang.OutOfMemoryError:Metaspace

/**
 * 描述:GC overhead Limit
 * jvm参数配置演示:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+MaxDirectMemorySize=5m
 * GC回收时间过长会抛出OutOfMemroyError,过长的定义是,超过98%的时间来做GC并且只回收了不到2%的堆内存
 * 连续多次GC都只是回收了不到2%的极端情况下才会抛出,假如不抛出GC Overhead limit错误会发生什么呢?
 * CPU使用率一直是100%,而GC没有任何成功
 *
 * @author xinjiao.yu@marketin.cn
 * @create 2020/2/24 21:41
 * @since 2.16.3
 */
public class GCOverheadDemo {
    public static void main(String[] args) {
        int i=0;
        List<String> list = new ArrayList<>();
        try{
            while(true){
                list.add(String.valueOf(++i).intern());
            }
        }catch (Exception e){
            System.out.println("**************i:"+i);
            e.printStackTrace();
            throw e;
        }
    }
}
/**
 * 描述: 配置参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
 * 故障现象:Exception in thread "main" java.lang.OutOfMemroyError:Direct buffer memory
 * 导致原因:
 * 写NIO程序经常使用ByteBuffer来读取或者写入数据,这是一种基于通道channel和缓冲区buffer的I/O方式,
 * 他可以使用natice函数库直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作
 * 这样能在一些场景中显著提高性能,因为避免了在java堆和native堆中来回复制数据
 *
 * ByteBuffer.allocate(capability)第一种方式是分配JVM内存,属于GC管辖范围,由于需要拷贝所以速度相对慢
 * ByteBuffer.allocateDirect(capability)第2中方式是分配OS本地内存,不属于GC管辖范围,不需要拷贝所以速度快
 * 但如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象就不会回收,这时候堆内存充足,但本地内存已经用光了
 * 再次尝试分配本地内存会出现OutOfMemoryError,那么程序直接崩溃
 *
 * @author xinjiao.yu@marketin.cn
 * @create 2020/2/24 22:00
 * @since 2.16.3
 */
public class DirectBufferMemoryDemo {
    public static void main(String[] args) {
//        System.out.println("配置的maxDirectMemory:"+(sun.misc.VM.maxDirectMemory()/(double)1024/1024)+"MB");
        ByteBuffer bb = ByteBuffer.allocateDirect(6*1024*1024);
    }
}
/**
 * 描述:
 * JVM参数:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m
 * java8以后使用metaspace来替代永久代
 * metaspace是方法区在hotspot中的实现,他与持久代最大的区别在于:metaspace并不在虚拟机内存中而是使用本地内存
 * 即在java8中,class metadata被存储在metaspace的native memeory
 * 永久代(java8后被元空间metaspace取代了)存放一下信息:
 * 虚拟机加载的类信息
 * 常量池
 * 静态变量
 * 即使编译后的代码
 *
 * @author xinjiao.yu@marketin.cn
 * @create 2020/2/25 13:33
 * @since 2.16.3
 */
public class MetaspaceOOMDemo {
    class OOMTest{}

    public static void main(String[] args) {
        int i = 0;
        while(true){
            i++;
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMTest.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invokeSuper(o,args);
                }
            });
        }
    }
}

2.四大垃圾回收方式:
 

①串行垃圾回收器(Serial)他为单线程环境设计且只使用一个线程进行垃圾回收,会暂停所有的用户线程,不适合生产环境②并行垃圾回收器(Parallel)多个垃圾收集线程并行工作,此时用户线程是暂停的,③并发垃圾回收器(CMS)用户线程和垃圾收集线程同时执行(不一定是并行,可能交替执行)不需要停顿用户线程,互联网公司多用他,适用对响应时间有要求的场景。④G1垃圾回收器,将堆内存分割成不同的区域然后并发的对其进行垃圾回收。

3.G1垃圾收集器:

.G1垃圾收集器是一种服务器端的垃圾收集器,应用在多处理器和大容量内存环境中,在实现高吞吐量的同时,尽可能的满足垃圾收集暂停时间的要求,另外还具有以下特性:①像CMS收集器一样,能与应用程序线程并发执行②整理空闲时间更快③需要更多的时间来预测GC停顿时间④不希望牺牲大量的吞吐量⑤不需要更大的Java Heap,他同CMS相比在以下方面表现的更出色:①G1是一个有整理内存过程的垃圾收集器,不会产生很多内存碎片②G1的Stop Thr World(STW)更可控,G1在停顿时间上添加了预测机制,用户可以指定期望停顿时间。G1主要改变是Eden,Survivor,Tenured等内存区域不在是连续的,而是变成了一个个大小一样的region,每个region从1m到32m不等,一个region有可能属于Eden,Survivor,Tenured内存区域。

4.G1垃圾收集器特点:

①G1能充分利用CPU,多核环境硬件优势,尽量缩短STW②G1整体上采用标记-整理算法,局部是通过复制算法,不会产生内存碎片③宏观上看G1之中不在区分年轻代和老年代,吧内存划分成多个独立的子区域④G1收集器里面将整个内存区域都混合在一起了,但其本身依然在小范围内要进行年轻代和老年代的区分,保留了新生代和老年代,但不再是物理隔离,而是一部分region的集合且不需要region是连续的⑤G1虽然是分代收集器,但整个内存分区不存在物理上的年轻代与老年代的区别,也不需要完全独立的survivor堆做复制准备,G1只有逻辑上的分代概念,每个分区都可能随G1的运行在不同代之间前后切换。

5.liunx命令:

①top,uptime系统性能命令的精简版②mpstat -P ALL 2查看所有CPU信息③pidstat -u 1 -p 进程号:每个进程使用cpu的用量分解信息③free应用程序可用内存数④内存查看额外:pidstat -p 进程号 -r 采样间隔秒数⑤df -h查看磁盘剩余空间数⑥iostat -xdk 2 3:磁盘IO性能评估⑦pidstat -d 采样间隔时间 -p 进程号:查看磁盘IO

6.假如生成环境出现cpu占用过高,请你谈谈你的分析思路和定位?

①先用top命令找出cpu占比最高的②ps -ef或者jps进一步定位,得知怎么样一个后台程序惹的事③定位到具体线程或者代码:ps -mp 进程 -o THREAD,tid,time,参数解释-m显示所有的线程-p pid进程使用cpu的时间,-o 改参数后是用户自定义格式④将需要的线程id转换成16进制格式(英文小写格式)⑤jstack 进程id | grep tid(16进制线程id小写英文) -A60

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!