zoukankan      html  css  js  c++  java
  • 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());
                }
            }
  • 相关阅读:
    Flexbox 可视化属性
    latex 数学公式
    迭代器模式 rx 应用
    小程序开发 easy-less 配置
    react-devtool 消息处理渲染 源码理解
    csrf jsonp
    koa1 源码详解1
    Immutable api example
    es6 ajax
    lodash 替换 underscore
  • 原文地址:https://www.cnblogs.com/wanghongye/p/11512933.html
Copyright © 2011-2022 走看看