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());
}
}
JVM的前世今生的更多相关文章
- JVM基础系列第1讲:Java 语言的前世今生
Java 语言是一门存在了 20 多年的语言,其年纪比我自己还大.虽然存在了这么长时间,但 Java 至今都是最大的工业级语言,许多大型互联网公司均采用 Java 来实现其业务系统.大到国际电商巨头阿 ...
- JVM 揭秘:一个 class 文件的前世今生
本文转载自JVM 揭秘:一个 class 文件的前世今生 导语 引子:我们都知道,要运行一个包含 main 方法的 java 文件,首先要将其编译成 class 文件,然后加载 JVM 中,就可以运行 ...
- JVM学习第一天(虚拟机的前世今生与与Java的内存区域)
其实说JVM的时候有很多人会懵, 也很不理解,我会写Java代码就可以了,我干嘛要学这个,其实不是的,学习JVM是很有必要性的; 为什么要了解JVM 1:写出更好,更健壮的Java程序; 2:提高Ja ...
- JVM(五)垃圾回收器的前世今生
全文共 2195 个字,读完大约需要 8 分钟. 如果垃圾回收的算法属于内存回收的方法论的话,那本文讨论的垃圾回收器就属于内存回收的具体实现. 因为不同的厂商(IBM.Oracle),实现的垃圾回收器 ...
- Python之路【第一篇】:Python前世今生
Python简介 Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解 ...
- Python前世今生
Python前世今生 Python简介 Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时 ...
- Python前世今生以及种类、安装环境
一.Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为A ...
- JVM基础系列第15讲:JDK性能监控命令
查看虚拟机进程:jps 命令 jps 命令可以列出所有的 Java 进程.如果 jps 不加任何参数,可以列出 Java 程序的进程 ID 以及 Main 函数短名称,如下所示. $ jps 6540 ...
- JVM基础系列第14讲:JVM参数之GC日志配置
说到 Java 虚拟机,不得不提的就是 Java 虚拟机的 GC(Garbage Collection)日志.而对于 GC 日志,我们不仅要学会看懂,而且要学会如何设置对应的 GC 日志参数.今天就让 ...
随机推荐
- 【内推】微软北京深圳招聘多名Cloud Solution Architect
Azure is the most comprehensive, innovative and flexible cloud platform today and Microsoft is hirin ...
- 【spring】jdbcTemplate之sql参数注入
demo @Repository("jdbcDao") public class JdbcTemplateDao { @Autowired private JdbcTemplate ...
- 随机定时修改密码change_passwd.sh
change_passwd.sh #!/bin/sh /usr/bin/chattr -i /etc/passwd /etc/shadow /etc/group /etc/gshadow /usr/b ...
- 剑指offer-面试题9-用两个栈实现队列-栈和队列
/* 题目: 用两个栈实现一个队列.队列声明如下. */ /* 思路: 将值压入stack1,再从stack1弹出到stack2,则为先进先出. appendTail时直接压入stack1即可,当st ...
- 学习django3过程中的坑
最近跟着Django by Example 2015学习,可老想用最新版的Django3.在学的过程中可踩了不少坑. 今天就又碰到一个: 在这本书中96页有这样的代码: url(r'^login/$' ...
- tp5使用PHPexcel扩展导出excel表
1,使用composer安装phpexcel包: composer require phpoffice/phpexcel 2,在控制器中创建方法: (1)使用PHPexcel扩展.代码如下 /** * ...
- Cloud开发动态列的简单账表
业务场景:客户需要根据过滤条件的不同显示不同的列.如下方式可以实现动态的列名. using System;using System.Collections.Generic;using System.L ...
- 在source insight project中删除文件夹或者文件的通用方法
1.删除文件夹或者文件在硬盘上的数据 2.project->synchronize files...看到如下图,然后勾选remove missing files from project
- VSCode常用插件之open in browser使用
更多VSCode插件使用请访问:VSCode常用插件汇总 open in browser安装完这个插件就可以在编辑器菜单右键html,在默认浏览器打开了,高级使用暂未了解,请自行其它文章学习
- 题解【AcWing279】自然数拆分
题面 因为题目中说参与加法运算的数可以重复,由此可以想到完全背包计数问题. 完全背包计数问题与 \(01\) 背包计数问题只有一个不同: \(01\) 背包计数问题的第二维循环是倒叙循环,而完全背包计 ...