性能调优实战案例2-对某段代码内存的计算
性能调优实战案例2-对某段代码内存的计算
1、问题
有一个查询,一次性将50万条记录查询、加载到内存中。如何通过JVM监控和根据一些监控数据推理出这50万条数据大概占用的内存大小?
2、分析
2.1、最直接的思路如下:
第一步,先取得加载数据前的内存大小
第二步,加载数据到内存中
第三步,再取得加载数据后的内存大小
第四步,求前后内存的差值
简单来说,在Java中就是load数据前后,堆大小的比较。
3、解决方案
3.1、java.lang.management.MemoryMXBean
package memorymxbean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName Main
* @Description TODO 类作用描述
* @Author Dave Ding
* @CreateDate 2019/7/11 19:03
* @Version V1.0
**/
public class Main {
public static void main(String[] args){
MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
MemoryUsage m = mbean.getHeapMemoryUsage();
long start = m.getUsed();
System.out.println("-------------------开始统计内存:"+start);
// 业务代码
List list = new ArrayList<Integer>();
for(int i=0;i<500000;i++){
list.add(i);
}
mbean = ManagementFactory.getMemoryMXBean();
m = mbean.getHeapMemoryUsage();
long end = m.getUsed();
System.out.println("-------------------结束统计内存:"+end);
System.out.println("-------------------差值:"+(end-start));
}
}
3.2、jvisualvm
步骤:
程序稳定运行5-10分钟后,打开jvisualvm,连接上运行程序的tomcat,接着执行一次GC,记录下GC后已使用的堆大小a,然后执行一下加载数据的操作,然后观察内存的变化,记录下此时堆大小的峰值b,两个值求差。重复测试10次左右,取差值之和的平均值。这个值大概就是这批数据的堆大小了。
存在问题
当数据量较小时,取得平均值不准确。
3.3、jmx
3.4、arthas
3.5、其它
(1)根据表结构计算
(2)根据String对象中char的大小计算
不过这两种方法需要计算,而且不能简单地累加。暂时没有研究。
3、延伸思考
3.1、Java一下子将50万条数据加载到内存中,会造成什么问题?
- 加大服务器内存压力
- 内存溢出问题
3.2、Java导出Excel数据量过大(50万以上)内存溢出如何解决?
- 用临时文件,先写在临时文件中,在写入excel中
- 多文件打包
- xml转Excel
- 多sheet
4、参考
(1)https://bbs.csdn.net/topics/390924117?page=1
(2)MemoryMXBean:https://blog.csdn.net/liuwei_csd/article/details/83327782
(3)arthas:https://blog.csdn.net/xiao_jun_0820/article/details/82774796
(4)jmx:https://www.jianshu.com/p/fa4e88f95631
(5)Java计算一个对象占用内存的大小:
https://blog.csdn.net/bobpauline/article/details/20699233
https://www.cnblogs.com/E-star/p/10222250.html
(6)换算工具
推荐阅读