JVM的前世今生

前世

jvm的数据区

分别是方法区(Method Area),Java栈(Java stack),本地方法栈(Native Method Stack),堆(Heap),程序计数器(Program Counter Register)

 

 堆

在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被划分为

三个区域:Eden、From Survivor、To Survivor。

新生代。新建的对象都是用新生代分配内存,Eden空间不足的时候,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRatio来控制Eden和Survivor的比例旧生代。用于存放新生代中经过多次垃圾回收仍然存活的对象。

 

 

 

gc的触发条件

充分了解了jvm的内存结构之后,下面我们就来说说什么情况下会触发gc。触发full gc的情况主要有这几种:

(1)System.gc()方法的调用。此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI(Java远程方法调用)调用System.gc。

(2)旧生代空间不足。旧生代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出错误:java.lang.OutOfMemoryError: Java heap space 。为避免以上两种状况引起的FullGC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。

(3)Permanet Generation空间满了。Permanet Generation中存放的为一些class的信息等,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出错误信息:java.lang.OutOfMemoryError: PermGen space 。为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。

(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存。如果发现统计数据说之前Minor GC的平均晋升大小比目前old gen剩余的空间大,则不会触发Minor GC而是转为触发full GC。

(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

 

今生

(1)我们在上传文件写入数据库时,如果同一时间写入上万数据,会导致fullgc

日志如下;

ownerThread current state is BLOCKED, current stackTrace,java.lang.OutOfMemoryError: GC overhead limit exceeded 

问题代码:

        List<Map<String, Object>> res;
        try {
            URL url = new URL(task.getTaskUrl());
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
    
            InputStream inputStream = new BufferedInputStream(conn.getInputStream());
    
            res = ExcelUtil.handleExcel(inputStream);
        } catch (IOException e){
            log.error(String.format("任务%s,下载解析异常{}", task.getId()), e);
            task.setRemark(e.getMessage());
            task.setStatus(BatchQueryStatusEnum.VERIFY_FAIL.getCode());
            batchQueryTaskDAO.update(task);
            return false;
        }

使用阿里的easyexcel解决fullgc问题

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>easyexcel</artifactId>
                <version>1.1.2-beat1</version>
            </dependency>

 

        List<Map<String, String>> res = new ArrayList<>();
        try {
            URL url = new URL(task.getTaskUrl());
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
    
            InputStream inputStream = new BufferedInputStream(conn.getInputStream());
    
            ExcelListener excelListener = new ExcelListener(MAX_COUNT, res);
    
            ExcelReader excelReader = EasyExcelFactory.getReader(inputStream, excelListener);
            excelReader.read();

  

(2)我们在读数据库写入excel时,如果同一时间写入上万数据,同一时间循环写入大量对象,导致服务宕机

问题代码:


        List<BatchQueryDetailDTO> list = batchQueryDetailService.query(id, type == 1);
        
        try {
            XSSFWorkbook wb = this.handle(list, apiName, type);
            StringBuilder sb = new StringBuilder();
            sb.append("批量查询").append(ThreadSafeDateUtil.format(new Date(), "yyyyMMddHHmmss")).append(".xlsx");
            String excelName = sb.toString();
            
            ExcelUtil.export(response, wb, excelName);
        } catch (Exception e) {
            log.error(String.format("taskId=%d导出批量查询失败,{}", id), e);
        }
        
    }

 分页解决大量创建对象问题

int pageSize = 2000;
        List<BatchQueryDetailDTO> list = new ArrayList<>();
        Page<BatchQueryDetailDTO> pageResult = batchQueryDetailService.query(id, 1, pageSize,type == 1);
        list.addAll(pageResult.getItems());
        
        int totalPage = pageResult.getTotalNumber() / pageSize + 1;
        for(int i = 2; i <= totalPage; i++) {
            pageResult = batchQueryDetailService.query(id, i, pageSize,type == 1);
            if(CollectionUtils.isNotEmpty(pageResult.getItems())){
                list.addAll(pageResult.getItems());
            }
        }

 

posted @ 2019-09-12 17:11  YOU_CAN  阅读(310)  评论(0编辑  收藏  举报