jvm一问一答

来源:互联网 发布:云烟 淘宝客 编辑:程序博客网 时间:2024/04/30 00:49

本文来自葛一鸣的jvm培训课程


写一个程序,让程序在运行之后,最终抛出由于Perm区溢出引起的OOM,给出运行的jdk版本,程序源码,运行参数,并说明你的基本思路

/** 1. jdk 1.7 2. @author bwx 3. @date 2017/11/16 4. question : 要求perm区溢出.Permanent 即 持久代(Permanent Generation),主要存放的是Java类定义信息,与垃圾收集器要收集的Java对象关系不大。 5. answers : 可以设置一个较小的MaxPermSize,但是必须要让jvm起来。然后载入类,实例化该类(**必须的**)。 6. jvm 参数 -server -XX:PermSize=1m -XX:MaxPermSize=4m */public class PermGenOutOfMemory {    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {        Class<?> aClass = Class.forName("java.security.MessageDigest");        Object o = aClass.newInstance();        while (true) {        }    }}

问:What is a StackOverflowError, what causes it, and how should I deal with them?

答:这里写链接内容
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
解决方法:增加-xxs 参数大小,使函数调用终止。


问:写一个程序,尽量产生STW现象。给出代码和启动JVM参数。并附上GC的log日志,标出停顿的时间

答:

/** * @author bwx * @date 2017/11/17 * -Xmx64M 最大堆大小    -Xms64M 初始堆大小    -XX:+UseSerialGC 老年代垃圾回收算法    -XX:+PrintGCDetails    -Xmn1m  年轻代大小    -XX:PretenureSizeThreshold=50 超过这个大小 直接进入老年代    -XX:MaxTenuringThreshold=1  多少次minor GC 进入老年代 * 垃圾回收算法:为让stw时间较长,增大年老代空间和选用serial old垃圾算法进行回收老年代 * jvm 参数 -Xmx64M -Xms64M -XX:+UseSerialGC -XX:+PrintGCDetails -Xmn1m -XX:PretenureSizeThreshold=50 -XX:MaxTenuringThreshold=1 * 输出GC log: * [GC[DefNew: 960K->63K(960K), 0.0007489 secs] 64438K->63775K(65472K), 0.0007749 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]    time:29706    time:29806    [GC[DefNew: 959K->63K(960K), 0.0009279 secs] 64705K->64117K(65472K), 0.0009465 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]    time:29907    time:30007    [GC[DefNew: 959K->63K(960K), 0.0008833 secs] 65034K->64413K(65472K), 0.0009006 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]    time:30108    [GC[DefNew: 959K->959K(960K), 0.0000109 secs][Tenured: 64364K->64511K(64512K), 0.0519109 secs] 65324K->64647K(65472K), [Perm : 3236K->3236K(21248K)], 0.0519510 secs] [Times: user=0.05 sys=0.00, real=0.05 secs]    [Full GC[Tenured: 64511K->64511K(64512K), 0.0437616 secs] 64665K->64654K(65472K), [Perm : 3236K->3236K(21248K)], 0.0437844 secs] [Times: user=0.05 sys=0.00, real=0.04 secs]    [Full GC[Tenured: 64511K->64511K(64512K), 0.0446344 secs] 64654K->64654K(65472K), [Perm : 3236K->3236K(21248K)], 0.0446526 secs] [Times: user=0.05 sys=0.00, real=0.04 secs]    =====准备清理=====:110622    time:30352    [Full GC[Tenured: 64511K->4409K(64512K), 0.0130335 secs] 64979K->4409K(65472K), [Perm : 3237K->3237K(21248K)], 0.0130716 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]    time:30466    time:30566    [GC[DefNew: 896K->64K(960K), 0.0006367 secs] 5331K->4786K(65472K), 0.0006646 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]    time:30667    [GC[DefNew: 960K->64K(960K), 0.0005735 secs] 5753K->5107K(65472K), 0.0005905 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]    time:30767    time:30867 */public class StopTheWorld {    private static final long starttime=System.currentTimeMillis();    private HashMap<Long,byte[]> map=new HashMap<Long,byte[]>();    public static void main(String[] args) throws InterruptedException {        StopTheWorld stw=new StopTheWorld();        stw.start();    }    private void start() throws InterruptedException {        while(true){            try {                for(int i=0;i<1024;i++){                    map.put(System.nanoTime(), new byte[512]);                }            } catch (OutOfMemoryError e) {                //在不可以分配的时候,进行清理部分空间,继续运行,这样会很快产生下一次垃圾回收                System.out.println("=====准备清理=====:"+map.size());                map.clear();            }            long t=System.currentTimeMillis()-starttime;            System.out.println("time:"+t);            Thread.sleep(100);        }    }}
  1. 在我的机器上,minor gc(年轻代GC)会大概花费1毫秒的时间,平均每两次循环发生一次minor gc。
  2. full GC大概花费10毫秒。

问:是否有方法尽可能减少一次STW停顿时间?由此带来的弊端是什么?

答:减少一次STW停顿时间,我这里从三个方面回答,一个是垃圾算法选择,一个是程序使用堆设置,无用对象尽早释放
1、垃圾算法选择:现在都是多核cpu,可以采用并行和并发收集器,如果是响应时间优化的系统应用 ,则jdk6版本一般选择的垃圾回收算法是:XX:+UseConcMarkSweepGC,即cms收集器,这个收集器垃圾回收时间短,但是垃圾回收总时间变长,使的降低吞吐量,算法使用的是标记-清除,并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生”碎片”,使得运行效率降低.CMSFullGCsBeforeCompaction此值设置运行多少次GC以后对内存空间进行压缩,整理

2、程序使用堆设置:应该根据程序运行情况,通过Jvm垃圾回收分析,设置一个比较合适的堆大小,不能一意味的将堆设置过大,导致程序回收很大一块空间,所以会导致stw时间较长,

3、无用对象尽早释放:使用的对象,如果没有用,尽早设置null,尽量在年轻代将对象进行回收掉,可以减少full gc停顿时长

原创粉丝点击