天道酬勤,学无止境

java 导出 excel 最佳实践,java 大文件 excel 避免OOM(内存溢出) exce

产品需求

产品经理需要导出一个页面的所有的信息到 EXCEL 文件。

需求分析

对于 excel 导出,是一个很常见的需求。

最常见的解决方案就是使用 poi 直接同步导出一个 excel 文件。

客户体验 & 服务性能

  • 客户体验

如果导出的文件比较大,比如几十万条数据,同步导出页面就会卡主,用户无法进行其他操作。

  • 服务性能

导出的时候,任务比较耗时就会阻塞主线程。

如果导出的服务是暴露给外部(前后端分离),这种大量的数据传输十分消耗性能。

解决方案

使用异常处理导出请求,后台 MQ 通知自己进行处理。

MQ 消费之后,多线程处理 excel 文件导出,生成文件后上传到 FTP 等文件服务器。

前端直接查询并且展现对应的任务执行列表,去 FTP 等文件服务器下载文件即可。

EXCEL 导出需要考虑的问题

OOM

正常的 poi 在处理比较大的 excel 的时候,会出现内存溢出。

网上的解决方案也比较多。

比如官方的 SXSSF (Since POI 3.8 beta3) 解决方式。

或者使用封装好的包

  1. easypoi ExcelBatchExportServer

  2. hutool BigExcelWriter

原理都是强制使用 xssf 版本的Excel

你也可以使用 easyexcel,当然这个注释文档有些欠缺,而且设计的比较复杂,不是很推荐。

我这里使用的是 hutool BigExcelWriter,
懒得自己再写一遍。

FULL GC

如果一次查询 100W 条数据库,然后把这些信息全部加载到内存中,是不可取的。

建议有2个:

  1. 限制每一次分页的数量。比如一次最多查询 1w 条。分成 100 次查询。(必须)

  2. 限制查询得总条数。比如限制为最多 10W 条。(根据实际情况选择)

虽然使用者提出要导出类似于 3 个月的所有信息,但是数量太多,毫无意义。(提出者自己可能体会不到)

尽量避免 FULL-GC 的情况发生,因为目前的所有方式对于 excel 的输出流都会占用内存,100W 条很容易导致 FULL-GC。

数据库的压力

去数据库读取的时候一定要记得分页,免得给数据库太大的压力。

一次读取太多,也会导致内存直线上升。

比如 100W 条数据,则分成 100 次去数据库读取。

网络传输

传统的 excel 导出,都是前端一个请求,直接 HTTP 同步返回。导出 100W 条,就在那里傻等。

这客户体验不友好,而且网络传输,系统占用多种问题。

建议使用异步处理的方式,将文件上传到文件服务器。前端直接去文件服务器读取。

编程的便利性

对于上面提到的工具,比如 Hutool,在表头的处理方面没法很方便的统一。

你可以自己定义类似于 easypoi/easyexcel 中的注解,自己反射解析。

然后统一处理表头即可。

IExcel 方便优雅的 excel 框架

特性

  • OO 的方式操作 excel,编程更加方便优雅。

  • sax 模式读取,SXSS 模式写入。避免 excel 大文件 OOM。

  • 基于注解,编程更加灵活。

  • 写入可以基于对象列表,也可以基于 Map,实际使用更加方便。

  • 设计简单,注释完整。方便大家学习改造。

后期特性

  • 读取跳过空白行

  • excel 样式相关的注解开发

创作缘由

实际工作和学习中,apache poi 操作 excel 过于复杂。

近期也看了一些其他的工具框架:

  • easypoi

  • easyexcel

  • hutool-poi

都或多或少难以满足自己的实际需要,于是就自己写了一个操作 excel 导出的工具。

快速开始

引入 Jar

使用 maven 管理。

<dependency>
     <groupId>com.github.houbb</groupId>
     <artifactId>iexcel</artifactId>
     <version>0.0.2</version>
</dependency>

定义对象

你可以直接参考 ExcelUtilTest.java

定义一个需要写入/读取的 excel 对象。

  • ExcelFieldModel.java

只有声明了 @ExcelField 的属性才会被处理,使用说明:@ExcelField

public class ExcelFieldModel {

    @ExcelField
    private String name;

    @ExcelField(headName = "年龄")
    private String age;

    @ExcelField(mapKey = "EMAIL", writeRequire = false, readRequire = false)
    private String email;

    @ExcelField(mapKey = "ADDRESS", headName = "地址", writeRequire = true)
    private String address;

    //getter and setter
}

写入例子

IExcelWriter 的实现

IExcelWriter 有几个实现类,你可以直接 new 或者借助 ExcelUtil 类去创建。

IExcelWriter 实现类 ExcelUtil 如何创建 说明
HSSFExcelWriter ExcelUtil.get03ExcelWriter() 2003 版本的 excel
XSSFExcelWriter ExcelUtil.get07ExcelWriter() 2007 版本的 excel
SXSSFExcelWriter ExcelUtil.getBigExcelWriter() 大文件 excel,避免 OOM

IExcelWriter 接口说明

写入到 2003

  • excelWriter03Test()

一个将对象列表写入 2003 excel 文件的例子。

/**
 * 写入到 03 excel 文件
 */
@Test
public void excelWriter03Test() {
    // 待生成的 excel 文件路径
    final String filePath = "excelWriter03.xls";

    // 对象列表
    List<ExcelFieldModel> models = buildModelList();

    try(IExcelWriter excelWriter = ExcelUtil.get03ExcelWriter();
        OutputStream outputStream = new FileOutputStream(filePath)) {
        // 可根据实际需要,多次写入列表
        excelWriter.write(models);

        // 将列表内容真正的输出到 excel 文件
        excelWriter.flush(outputStream);
    } catch (IOException e) {
        throw new ExcelRuntimeException(e);
    }
}
  • buildModelList()
/**
 * 构建测试的对象列表
 * @return 对象列表
 */
private List<ExcelFieldModel> buildModelList() {
    List<ExcelFieldModel> models = new ArrayList<>();
    ExcelFieldModel model = new ExcelFieldModel();
    model.setName("测试1号");
    model.setAge("25");
    model.setEmail("123@gmail.com");
    model.setAddress("贝克街23号");

    ExcelFieldModel modelTwo = new ExcelFieldModel();
    modelTwo.setName("测试2号");
    modelTwo.setAge("30");
    modelTwo.setEmail("125@gmail.com");
    modelTwo.setAddress("贝克街26号");

    models.add(model);
    models.add(modelTwo);
    return models;
}

一次性写入到 2007 excel

有时候列表只写入一次很常见,所有就简单的封装了下:

/**
 * 只写入一次列表
 * 其实是对原来方法的简单封装
 */
@Test
public void onceWriterAndFlush07Test() {
    // 待生成的 excel 文件路径
    final String filePath = "onceWriterAndFlush07.xlsx";

    // 对象列表
    List<ExcelFieldModel> models = buildModelList();

    // 对应的 excel 写入对象
    IExcelWriter excelWriter = ExcelUtil.get07ExcelWriter();

    // 只写入一次列表
    ExcelUtil.onceWriteAndFlush(excelWriter, models, filePath);
}

读取例子

excel 读取时会根据文件名称判断是哪个版本的 excel。

IExcelReader 的实现

IExcelReader 有几个实现类,你可以直接 new 或者借助 ExcelUtil 类去创建。

IExcelReader 实现类 ExcelUtil 如何创建 说明
ExcelReader ExcelUtil.getExcelReader() 小文件的 excel 读取实现
Sax03ExcelReader ExcelUtil.getBigExcelReader() 大文件的 2003 excel 读取实现
Sax07ExcelReader ExcelUtil.getBigExcelReader() 大文件的 2007 excel 读取实现

IExcelReader 接口说明

excel 读取的例子

/**
 * 读取测试
 */
@Test
public void readWriterTest() {
    File file = new File("excelWriter03.xls");
    IExcelReader<ExcelFieldModel> excelReader = ExcelUtil.getExcelReader(file);
    List<ExcelFieldModel> models = excelReader.readAll(ExcelFieldModel.class);
    System.out.println(models);
}

ExcelField 注解说明

@ExcelField 的属性说明如下:

属性 类型 默认值 说明
mapKey String "" 仅用于生成的入参为 map 时,会将 map.key 对应的值映射到 bean 上。如果不传:默认使用当前字段名称
headName String "" excel 表头字段名称,如果不传:默认使用当前字段名称
writeRequire boolean true excel 文件是否需要写入此字段
readRequire boolean true excel 文件是否读取此字段

IExcelWriter 接口说明

/**
 * 写出数据,本方法只是将数据写入Workbook中的Sheet,并不写出到文件<br>
 * <p>
 * data中元素支持的类型有:
 *  <pre>
 * 1. Bean,既元素为一个Bean,第一个Bean的字段名列表会作为首行,剩下的行为Bean的字段值列表,data表示多行 <br>
 * </pre>
 * @param data 数据
 * @return this
 */
IExcelWriter write(Collection<?> data);

/**
 * 写出数据,本方法只是将数据写入Workbook中的Sheet,并不写出到文件<br>
 *  将 map 按照 targetClass 转换为对象列表
 *  应用场景: 直接 mybatis mapper 查询出的 map 结果,或者其他的构造结果。
 * @param mapList map 集合
 * @param targetClass 目标类型
 * @return this
 */
IExcelWriter write(Collection<Map<String, Object>> mapList, final Class<?> targetClass);

/**
 * 将Excel Workbook刷出到输出流
 *
 * @param outputStream 输出流
 * @return this
 */
IExcelWriter flush(OutputStream outputStream);

指定 sheet

创建 IExcelWriter 的时候,可以指定 sheet 的下标或者名称。来指定写入的 sheet。

是否包含表头

创建 IExcelWriter 的后,可以调用 excelWriter.containsHead(bool) 指定是否生成 excel 表头。

IExcelReader 接口说明

/**
 * 读取当前 sheet 的所有信息
 * @param tClass 对应的 javabean 类型
 * @return 对象列表
 */
List<T> readAll(Class<T> tClass);

/**
 * 读取指定范围内的
 * @param tClass 泛型
 * @param startIndex 开始的行信息(从0开始)
 * @param endIndex 结束的行信息
 * @return 读取的对象列表
 */
List<T> read(Class<T> tClass, final int startIndex, final int endIndex);

指定 sheet

创建 IExcelReader 的时候,可以指定 sheet 的下标或者名称。来指定读取的 sheet。

注意:大文件 sax 读取模式,只支持指定 sheet 的下标。

是否包含表头

创建 IExcelReader 的后,可以调用 excelReader.containsHead(bool) 指定是否读取 excel 表头。

拓展阅读

excel 导出最佳实践

iexcel 框架

标签

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • java 导出 excel 最佳实践,大文件 excel 避免OOM(内存溢出) 框架-02-API
    项目简介 IExcel 用于优雅地读取和写入 excel。 避免大 excel 出现 oom,简约而不简单。。 特性 OO 的方式操作 excel,编程更加方便优雅。 sax 模式读取,SXSS 模式写入。避免 excel 大文件 OOM。 基于注解,编程更加灵活。 写入可以基于对象列表,也可以基于 Map,实际使用更加方便。 设计简单,注释完整。方便大家学习改造。 变更日志 变更日志 v0.0.4 主要变化 引入 ExcelBs 引导类,优化使用体验。 创作缘由 实际工作和学习中,apache poi 操作 excel 过于复杂。 近期也看了一些其他的工具框架: easypoi easyexcel hutool-poi 都或多或少难以满足自己的实际需要,于是就自己写了一个操作 excel 导出的工具。 快速开始 环境要求 jdk1.7+ maven 3.x 引入 jar 使用 maven 管理。 <dependency> <groupId>com.github.houbb</groupId> <artifactId>iexcel</artifactId> <version>0.0.4</version> </dependency> Excel 写入 示例 /** * 写入到 excel 文件 * 直接将列表内容写入到文件 */ public void writeTest() {
  • 导入和导出Excel-最好的库是什么? [关闭](Import and Export Excel - What is the best library? [closed])
    问题 关闭。 此问题不符合堆栈溢出准则。 它当前不接受答案。 想要改善这个问题吗? 更新问题,使它成为Stack Overflow的主题。 7年前关闭。 改善这个问题 在C#中的一个ASP.NET应用程序中,我们进行某些数据收集(SubSonic收集)并将其导出到Excel。 我们还希望以特定格式导入Excel文件。 我正在寻找可以用于此目的的库。 要求: Excel 2007文件(Excel 2003是否支持超过64k行?我还需要更多。) 不需要服务器上的Excel 接受类型化的集合,如果可以的话,尝试将数字字段作为Excel中的数字放置。 适用于大型文件(100k至10M)-足够快。 导出GUID时不会崩溃! 无需花钱(没有像aspose那样的企业库)。 自由永远是伟大的,但可以成为商业图书馆。 您推荐什么图书馆? 您是否将其用于大量数据? 还有其他解决方案吗? 现在,我正在使用一个简单的工具来生成HTML,以后再由Excel加载该HTML,但是我却失去了一些功能,加上Excel在加载它时会抱怨。 我不需要生成图表或类似的东西,只需导出原始数据即可。 我正在考虑平面CSV文件,但是Excel是客户要求。 如果我有可以与Excel相互转换的工具,则可以直接使用CSV。 鉴于Excel 2007是基于xml(和压缩文件)的文件格式,我想这种类型的库应该很容易找到。 但是
  • 什么时候可以调用GC.Collect?(When is it acceptable to call GC.Collect?)
    问题 一般建议是,您不应从代码中调用GC.Collect ,但是此规则的例外是什么? 我只能想到一些非常特殊的情况,在这些情况下强制进行垃圾回收是有意义的。 想到的一个示例是一项服务,该服务每隔一段时间唤醒一次,执行一些任务,然后长时间睡眠。 在这种情况下,最好强制执行一次收集,以防止即将闲置的进程保留所需的更多内存。 还有其他可以接受调用GC.Collect吗? 回答1 如果您有充分的理由相信大量对象(尤其是您怀疑是第1代和第2代的对象)现在可以进行垃圾收集了,那么就性能而言,这是一个合适的收集时间。 一个很好的例子是,如果您刚刚关闭了一个大表格。 您知道现在可以对所有UI控件进行垃圾回收,并且由于关闭表单而造成的短暂暂停可能对用户而言并不明显。 更新2.7.2018 从.NET 4.5开始-有GCLatencyMode.LowLatency和GCLatencyMode.SustainedLowLatency 。 当进入和退出这两种模式时,建议您使用GC.Collect(2, GCCollectionMode.Forced)强制使用完整的GC。 从.NET 4.6开始-有GC.TryStartNoGCRegion方法(用于设置只读值GCLatencyMode.NoGCRegion )。 这本身可以执行完整的阻塞垃圾回收,以释放足够的内存,但是鉴于我们在一段时间内不允许使用GC
  • POI及EasyExcel使用
    POI和EasyExcel 使用场景 1、讲用户的信息导出Excel表格(导出数据…) 2、将Excel表中的信息录入到网站数据库(大量信息上传),减轻网站录入量! 开发中经常会设计到Excel的处理,如Excel的导出,Excel导入数据库! 目前操作Excel比较流行的就是Apache POI 和阿里巴巴的 easyExcel! Apache POI Apache POI官网:https://poi.apache.org/ easyExcel easyExcel 官网:https://github.com/alibaba/easyexcel EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。 EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。 内存问题:POI是 全部先加载到内存OOM,在写入文件。EasyExcel 是一行一行读,逐个解析。 下图是EasyExcel和POI在解析Excel时的对比图。 easyExcel 文档:https://alibaba-easyexcel.github.io/ https://www.yuque.com/easyexcel/doc/ POI-Excel写 创建项目 1、创建maven项目 2、导入pom依赖 <
  • 10w 行级别数据的 Excel 导入优化记录
    需求说明 项目中有一个 Excel 导入的需求:缴费记录导入 由实施 / 用户 将别的系统的数据填入我们系统中的 Excel 模板,应用将文件内容读取、校对、转换之后产生欠费数据、票据、票据详情并存储到数据库中。 在我接手之前可能由于之前导入的数据量并不多没有对效率有过高的追求。但是到了 4.0 版本,我预估导入时Excel 行数会是 10w+ 级别,而往数据库插入的数据量是大于 3n 的,也就是说 10w 行的 Excel,则至少向数据库插入 30w 行数据。因此优化原来的导入代码是势在必行的。我逐步分析和优化了导入的代码,使之在百秒内完成(最终性能瓶颈在数据库的处理速度上,测试服务器 4g 内存不仅放了数据库,还放了很多微服务应用。处理能力不太行)。具体的过程如下,每一步都有列出影响性能的问题和解决的办法。 导入 Excel 的需求在系统中还是很常见的,我的优化办法可能不是最优的,欢迎读者在评论区留言交流提供更优的思路 一些细节 数据导入:导入使用的模板由系统提供,格式是 xlsx (支持 65535+行数据) ,用户按照表头在对应列写入相应的数据数据校验:数据校验有两种: 字段长度、字段正则表达式校验等,内存内校验不存在外部数据交互。对性能影响较小数据重复性校验,如票据号是否和系统已存在的票据号重复(需要查询数据库,十分影响性能) 数据插入:测试环境数据库使用 MySQL 5
  • 线上问题定位------内存瓶颈
    内存问题排查起来相对比CPU麻烦一些,场景也比较多。主要包括OOM、GC问题和堆外内存。一般来讲,我们会先用free命令先来检查一发内存的各种情况。 free free是查看内存使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存。 free -h -s 3表示每隔三秒输出一次内存情况,命令如下 [1014154@cc69dd4c5-4tdb5 ~]$ free total used free shared buff/cache available Mem: 119623656 43052220 45611364 4313760 30960072 70574408 Swap: 0 0 0 [1014154@cc69dd4c5-4tdb5 ~]$ free -h -s 3 total used free shared buff/cache available Mem: 114G 41G 43G 4.1G 29G 67G Swap: 0B 0B 0B total used free shared buff/cache available Mem: 114G 41G 43G 4.1G 29G 67G Swap: 0B 0B 0B Mem:是内存的使用情况。 Swap:是交换空间的使用情况。 total:系统总的可用物理内存和交换空间大小。 used:已经被使用的物理内存和交换空间
  • JVM之堆
    JVM之堆 核心概述 一个JVM实例值存在一个堆内存,堆也是Java内存管理的核心区域。 Java堆区在JVM启动的时候就被创建了,其空间大小也就确定了,是JVM管理的最大一块内存空间。《Java虚拟机规范》规定,堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(TLAB,Thread Local Allocation Buffer)。《Java虚拟机规范》中对Java堆的描述是:所有的对象实例以及数组都应当在运行时分配在堆上(但并不是全部)。数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置。 在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除。堆,是GC(垃圾收集器)执行垃圾回收的重点区域。 注意: Java 7之前和图上一模一样,Java 8把永久区换成了元空间(方法区) 堆逻辑上由”新生+养老+元空间“三个部分组成,物理上由”新生+养老“两个部分组成 当执行new Person();时,其实是new在新生区的伊甸园区,然后往下走,走到养老区,但是并未到元空间。 虽然说,逻辑上是将堆空间划分为新生代、老年代和永久代三部分,实际上是不考虑永久代(也就是Java8中提到的元空间)的,可以将其看做是方法区的落地实现。 注意: GC发生在伊甸园区
  • Java堆内存又溢出了!教你一招必杀技
    JAVA堆内存管理是影响性能主要因素之一。堆内存溢出是JAVA项目非常常见的故障,在解决该问题之前,必须先了解下JAVA堆内存是怎么工作的。 先看下JAVA堆内存是如何划分的,如图: JVM内存划分为堆内存和非堆内存,堆内存分为年轻代(Young Generation)、老年代(Old Generation),非堆内存就一个永久代(Permanent Generation)。 年轻代又分为Eden和Survivor区。Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例是8:1:1。 堆内存用途:存放的是对象,垃圾收集器就是收集这些对象,然后根据GC算法回收。 非堆内存用途:永久代,也称为方法区,存储程序运行时长期存活的对象,比如类的元数据、方法、常量、属性等。 在JDK1.8版本废弃了永久代,替代的是元空间(MetaSpace),元空间与永久代上类似,都是方法区的实现,他们最大区别是:元空间并不在JVM中,而是使用本地内存。元空间有注意有两个参数: MetaspaceSize :初始化元空间大小,控制发生GC阈值 MaxMetaspaceSize : 限制元空间大小上限,防止异常占用过多物理内存 为什么移除永久代? 移除永久代原因:为融合HotSpot JVM与JRockit VM(新JVM技术)而做出的改变
  • Spark java.lang.OutOfMemoryError:Java堆空间(Spark java.lang.OutOfMemoryError: Java heap space)
    问题 我的集群:1个主机,11个从机,每个节点有6 GB内存。 我的设置: spark.executor.memory=4g, Dspark.akka.frameSize=512 这是问题所在: 首先,我从HDFS到RDD读取了一些数据(2.19 GB): val imageBundleRDD = sc.newAPIHadoopFile(...) 其次,在此RDD上执行以下操作: val res = imageBundleRDD.map(data => { val desPoints = threeDReconstruction(data._2, bg) (data._1, desPoints) }) 最后,输出到HDFS: res.saveAsNewAPIHadoopFile(...) 当我运行程序时,它显示: ..... 14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Starting task 1.0:24 as TID 33 on executor 9: Salve7.Hadoop (NODE_LOCAL) 14/01/15 21:42:27 INFO cluster.ClusterTaskSetManager: Serialized task 1.0:24 as 30618515 bytes in 210 ms
  • Spark性能调优-Shuffle调优及故障排除篇
    Spark调优之Shuffle调优本节开始先讲解Shuffle核心概念;然后针对HashShuffle、SortShuffle进行调优;接下来对map端、reduce端调优;再针对Spark中的数据倾斜问题进行剖析及调优;最后是Spark运行过程中的故障排除。本文首发于公众号【五分钟学大数据】,本公号专注于大数据技术,分享高质量大数据原创技术文章。一、Shuffle的核心概念1. ShuffleMapStage与ResultStageShuffleMapStage与ResultStage在划分stage时,最后一个stage称为FinalStage,它本质上是一个ResultStage对象,前面的所有stage被称为ShuffleMapStage。ShuffleMapStage的结束伴随着shuffle文件的写磁盘。ResultStage基本上对应代码中的action算子,即将一个函数应用在RDD的各个partition的数据集上,意味着一个job的运行结束。2. Shuffle中的任务个数我们知道,Spark Shuffle分为map阶段和reduce阶段,或者称之为ShuffleRead阶段和ShuffleWrite阶段,那么对于一次Shuffle,map过程和reduce过程都会由若干个task来执行,那么map task和reduce task的数量是如何确定的呢
  • 捕获java.lang.OutOfMemoryError吗?(Catching java.lang.OutOfMemoryError?)
    问题 java.lang.Error文档说: 错误是Throwable的子类,它指示严重的问题,而合理的应用程序不应尝试捕获这些问题。 但随着java.lang.Error是的一个子类java.lang.Throwable ,我能赶上这个Throwable类型。 我了解为什么捕获这种异常不是一个好主意。 据我了解,如果我们决定捕获它,捕获处理程序不应自行分配任何内存。 否则,将再次引发OutOfMemoryError 。 所以,我的问题是: 捕获java.lang.OutOfMemoryError可能是个好主意吗? 如果我们决定捕获java.lang.OutOfMemoryError ,我们如何确保catch处理程序不会自行分配任何内存(任何工具或最佳实践)? 回答1 在许多情况下,您可能希望捕获OutOfMemoryError ,根据我的经验(在Windows和Solaris JVM上), OutOfMemoryError很少会成为JVM的丧钟。 捕获OutOfMemoryError只是一个很好的理由,那就是正常关闭,干净地释放资源并尽可能记录故障原因(如果仍然可以这样做)。 通常,由于无法用堆的其余资源满足的块内存分配而发生OutOfMemoryError 。 引发Error ,堆将包含与失败分配之前相同数量的已分配对象
  • 将多个data.frame导出到多个Excel工作表的简便方法(Easy way to export multiple data.frame to multiple Excel worksheets)
    问题 我很惊讶地发现没有简单的方法可以将多个data.frame导出到Excel文件的多个工作表中? 我试过xlsx包,看来它只能写一张纸(覆盖旧纸); 我也尝试了WriteXLS软件包,但是它总是给我错误... 我的代码结构是这样的:根据设计,对于每次迭代,输出数据帧(tempTable)和sheetName(sn)都会更新并导出到一个选项卡中。 for (i in 2 : ncol(code)){ ... tempTable <- ... sn <- ... WriteXLS("tempTable", ExcelFileName = "C:/R_code/../file.xlsx", SheetNames = sn); } 我可以导出到多个cvs文件,但是必须有一种简单的方法可以在Excel中做到这一点,对吗? 回答1 您可以使用xlsx软件包写入多张纸。 您只需要为每个数据框使用不同的sheetName ,并需要添加append=TRUE : library(xlsx) write.xlsx(dataframe1, file="filename.xlsx", sheetName="sheet1", row.names=FALSE) write.xlsx(dataframe2, file="filename.xlsx", sheetName="sheet2", append
  • 在Android中使用Intent在活动中传递android位图数据(Passing android Bitmap Data within activity using Intent in Android)
    问题 我在Activity1中有一个名为bmp的位图变量,我想将该位图发送到Activity2 以下是我用来传递其意图的代码。 Intent in1 = new Intent(this, Activity2.class); in1.putExtra("image",bmp); startActivity(in1); 在Activity2中,我尝试使用以下代码访问位图 Bundle ex = getIntent().getExtras(); Bitmap bmp2 = ex.getParceable("image"); ImageView result = (ImageView)findViewById(R.Id.imageView1); result.setImageBitmap(bmp); 该应用程序无一例外地运行,但是没有给出预期的结果 回答1 在将其添加到意图,将其发送和解码之前,将其转换为Byte数组。 //Convert to byte array ByteArrayOutputStream stream = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] byteArray = stream.toByteArray(); Intent
  • java中使用poi导出Excel详解
    java当初把核心处理设成Unicode,带来的好处是代码适应了多语言环境。然而由于老外的英语只有26个字母,有些情况下,一些程序员用8 位的byte处理,一不小心就去掉了CJK的高位。或者是由于习惯在程序中采用硬编码,还有多种原因,使得许多java应用在CJK的处理上很烦恼。还好 在POI HSSF中考虑到这个问题,可以设置encoding为双字节。 POI可以到www.apache.org下载到。编译好的jar主要有这样4个:poi包,poi Browser包,poi hdf包,poi hssf例程包。实际运行时,需要有poi包就可以了。如果你仅仅是为了熟悉POI hssf的使用,可以直接看POI的samples包中的源代码,并且运行它。hssf的各种对象都有例程的介绍。hssf提供的例程在 org.apache.poi.hssf.usermodel.examples包中,共有14个,生成的目标xls都是workbook.xls。如果 你想看更多的例程,可以参考hssf的Junit test cases,在poi的包的源代码中。hssf都有测试代码。 这里只对部分例程的实现做介绍。 HSSF提供给用户使用的对象在org.apache.poi.hssf.usermodel包中,主要部分包括Excell对象,样式和格式,还有辅助操作。有以下几种对象: HSSFWorkbook
  • 程序员怎样优雅度过35岁中年危机?妈妈再也不用担心我找工作了!
    开头 移动应用开发从逐渐开始火爆到如今也有小十年了,大部分的学校还是没有开放专门的课程。 目前市场上的大部分 Android 开发工程师大多数是自学或者是培训出身,用一段时间上手 Android 开发技能(畅销书作家 Josh Kaufman 提出,掌握正确的方法后,可以在短期内上手任何技能 ),而后进入一家公司或者接手一个项目培养实操能力、积累实战经验。 再之后呢,Android 开发初期之后怎么提升?怎么才能叫精通?方向在哪? 通常情况下,Android 工程师 1-3 年时间应该能从初级上升到中高级工程师,这个阶段主要就是技术的提升和经验的积累。 之后 1-3 年持续做到高级工程师,这个位置要求能独立完成整个模块,对项目架构有比较深入的了解,能够设计复杂模块的程序方案。 同时需要一定的管理能力,能够带新同事快速入手项目,所以这时候一般同时也担任了主程或者 Team Leader,部分参与项目的管理工作。 ANR面试题 1、什么是ANR Application Not Responding,页面无响应的对话框 2、发生ANR的条件 应用程序的响应性是由ActivityManager和WindowManager系统服务监视的,当ANR发生条件满足时,就会弹出ANR的对话框
  • Spark优化和故障处理
    文章目录 1 Spark性能优化1.1 直接方式1.2 常规性能调优1.2.1 最优资源配置1.2.2 RDD优化1.2.3 并行度的调节1.2.4 广播大变量1.2.5 Kryo序列化1.2.6 调节本地化等待时长 1.3 算子调优1.3.1 mappartitions1.3.2 foreachpartition优化数据库操作1.3.3 filter与coalesce的配合使用1.2.4 repartition解决SparkSQL低并行度问题1.2.5 优先使用reducebykey本地聚合 1.4 shuffle调优1.4.1 调整map端缓冲区的大小1.4.2 调节reduce端拉取数据缓冲区大小1.4.3 调节reduce端拉取数据重试次数1.4.4 调节reduce端拉取数据等待间隔1.4.5 调节SortShuffle排序操作阈值 1.5 JVM调优1.5.1 降低cache操作的内存占比1.5.2 调节Executor堆外内存1.5.3 调节连接等待时长 2 故障处理2.1 控制reduce端缓冲大小以避免OOM2.2 JVM GC导致的shuffle文件拉取失败2.3 解决各种序列化导致的报错2.4 解决算子函数返回NULL导致的问题2.5 解决YARN-CLIENT模式导致的网卡流量激增问题2.6 解决YARN-CLUSTER模式的JVM栈内存溢出无法执行问题2
  • JVM垃圾收集器与内存分配策略一(JVM堆、栈、方法区内存溢出案例)
    文章目录 前言JVM运行时数据区程序计数器虚拟机栈本地方法栈堆方法区直接内存 虚拟机栈OutOfMemoryError、StackOverflowError堆OutOfMemoryError方法区OutOfMemoryError直接内存OutOfMemoryError 前言 java与C++直接有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外的人想进去,墙内的人想出来,作为一个java工程师,接下来将带大家一探墙内秘密。 这篇文章是JVM垃圾收集器与内存分配策略模块学习的第一篇文章,主要是作为真正学习前的铺垫,主要会介绍一下JVM运行时数据区以及各个区域在什么情景下回出现内存溢出,下文会通过代码实战模拟JVM的各个区域的内存溢出情景,并加以分析。 JVM运行时数据区 程序计数器 程序计数器是很小的一块内存区域,用于记录当前线程正在执行的虚拟机字节码指令的地址。在多线程情况下,为了当前线程在获取到CPU资源后能够迅速恢复到上次执行的代码位置,所以每个线程都要有自己单独的程序计数器,且各个线程之间的程序计数器互不影响,独立储存,所以程序计数器属于线程隔离数据区。此区域也是唯一一个在《java虚拟机规范》中提到不会出现OutOfMemoryError异常的地方。 虚拟机栈 虚拟机栈也是线程私有的每个线程都会有一个虚拟机栈,生命周期与线程相同
  • 零碎知识点整理
    进程间通信方式 管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 死锁条件 互斥占有等待循环等待不可剥夺 解决死锁的方法分为死锁的预防,避免,检测与恢复 预防
  • JMM
    JMM 1.什么是JMM? JMM:(Java Memory Model 的缩写)JAVA 内存模型 2.作用是什么? 作用:缓存一致性协议,用于定义数据读写规则 JMM定义了线程工作内存和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory) JMM规定了内存主要划分为主内存和工作内存两种。此处的主内存和工作内存跟JVM内存划分(堆、栈、方法区)是在不同的层次上进行的,如果非要对应起来,主内存对应的是Java堆中的对象实例部分,工作内存对应的是栈中的部分区域,从更底层的来说,主内存对应的是硬件的物理内存,工作内存对应的是寄存器和高速缓存。 解决共享对象可见性问题:volatile或者synchronized 同步机制 Java Memory Model: Java内存模型 – 抽象概念, 理论定义了线程工作内存和主内存之间的抽象关系 线程之间的共享变量存储在主内存中 ----MAIN MEMORY每个线程都有一个私有的本地内存 ---- LOCAL MEMORY 与并发相关 OOM的种类和原因 java.lang.OutOfMemoryError内存泄漏(memory leak) 是指程序中一动态分配的堆内存由于某种原因程序未释放,造成系统内存的浪费
  • EasyPOI简单用例,简单有效
    用poi导出Excel表格,需要配置很多东西,也比较麻烦,这里使用poi的封装easypoi,可以快速配置,实现Excel或者word文件的导出。这里我们结合SpringMVC开发easypoi。 1,导入以下3个.jar包:这里是springMVC和easypoi所需的jar包,主要是easypoi-base和easypoi-web,其它都是关联所需的jar包,我们需要commons-lang3.jar包,开始使用commons-lang2.6版本会出现错误。 2,spring-mvc.xml配置如下: <!-- Bean解析器,级别高于默认解析器,寻找bean对象进行二次处理 --> <bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="0"> </bean> <!-- Excel 处理 根据用户输入进行对象处理 --> <bean id="jeecgExcelView" class="org.jeecgframework.poi.excel.view.JeecgSingleExcelView" /> <bean id="jeecgTemplateExcelView" class="org.jeecgframework