Spark中collect方法报错java.lang.OutOfMemoryError:Java heap space

本文分析了Spark中collect方法导致的`java.lang.OutOfMemoryError: Java heap space`错误,强调了collect操作在分布式环境中的弊端,如耗时和可能引发内存溢出。建议通过使用foreach、take或saveAsTextFile等方法规避问题。另外,介绍了collectPartitions作为替代选项,但其仍可能导致内存问题,返回二维数组。

具体报错信息:

在执行val arr = data.collect()的时候报错
java.lang.OutOfMemoryError:Java heap space

1.collect的作用

Spark内有collect方法,是Action操作里边的一个算子,这个方法可以将RDD类型的数据转化为数组,同时会从远程集群是拉取数据到driver端。

2.已知的弊端

首先,collect是Action里边的,根据RDD的惰性机制,真正的计算发生在RDD的Action操作。那么,一次collect就会导致一次Shuffle,而一次Shuffle调度一次stage,然而一次stage包含很多个已分解的任务碎片Task。这么一来,会导致程序运行时间大大增加,属于比较耗时的操作,即使是在local模式下也同样耗时。
其次,从环境上来讲,本机local模式下运行并无太大区别,可若放在分布式环境下运行,一次collect操作会将分布式各个节点上的数据汇聚到一个driver节点上,而这么一来,后续所执行的运算和操作就会脱离这个分布式环境而相当于单机环境下运行,这也与Spark的分布式理念不合。
最后,将大量数据汇集到一个driver节点上,并且像这样val arr = data.collect(),将数据用数组存放,占用了jvm堆内存,可想而知,是有多么轻松就会内存溢出。

3.如何规避

若需要遍历RDD中元素,大可不必使用collect,可以使用foreach语句;
若需要打印RDD中元素,可用take语句,返回数据集前n个元素,data.take(1000).foreach(println),这点官方文档里有说明;
若需要查看其中内容,可用saveAsTextFile方法。
总之,单机环境下使用collect问题并不大,但分布式环境下尽量规避,如有其他需要,手动编写代码实现相应功能就好。

4.补充:

collectPartitions:同样属于Action的一种操作,同样也会将数据汇集到Driver节点上,与collect区别并不是很大,唯一的区别是:collectPartitions产生数据类型不同于collect,collect是将所有RDD汇集到一个数组里,而collectPartitions是将各个分区内所有元素存储到一个数组里,再将这些数组汇集到driver端产生一个数组;collect产生一维数组,而collectPartitions产生二维数组。

在使用 Flink 的过程中,如果遇到 `java.lang.ClassNotFoundException: org.apache.flink.runtime.types.FlintScalaKryoInstantiator` 错误,通常是由于类路径(classpath)中缺少必要的依赖项或版本不兼容导致的。 该异常表明 JVM 在运行时无法找到指定的类 `org.apache.flink.runtime.types.FlinkScalaKryoInstantiator`。此类通常与 Flink 的序列化机制相关,尤其是在使用 Scala API 或某些需要 Kryo 序列化的场景下[^1]。 ### 解决方案 1. **检查 Flink 版本与依赖一致性** 确保所有使用的 Flink 模块版本一致。例如,如果你使用的是 Flink 1.17,则所有依赖项都应使用相同的版本号。Maven 配置示例如下: ```xml <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-scala_2.12</artifactId> <version>1.17.0</version> </dependency> <dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-runtime</artifactId> <version>1.17.0</version> </dependency> ``` 2. **排除冲突的依赖库** 如果项目中引入了其他可能与 Flink 内部依赖冲突的库(如 Guava、Kryo、commons-cli 等),建议通过 `<exclusion>` 标签进行排除,避免类加载冲突。例如: ```xml <dependency> <groupId>some.group</groupId> <artifactId>some-artifact</artifactId> <version>some.version</version> <exclusions> <exclusion> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </exclusion> </exclusions> </dependency> ``` 3. **检查运行环境中的 JAR 包** 确保提交任务时所使用的 Flink 版本与开发环境中编译所用的版本一致,并且所有必需的 JAR 文件都被正确打包并放置在 `lib/` 目录下。 4. **使用 `--classloader-check-verbose` 参数排查问题** 在提交作业时添加如下参数可以帮助更详细地查看类加载过程: ```bash bin/flink run -D classloader.check-verbose=true your-job.jar ``` 5. **确保使用正确的 Scala 版本** Flink 对 Scala 版本有严格的绑定要求,例如 Flink 1.17 支持 Scala 2.12 和 2.11。请确保项目中引用的 Scala 版本与 Flink 构建时使用的版本一致,否则可能导致类找不到的问题。 6. **清理和重建项目依赖** 使用 Maven 或 Gradle 清理并重新下载依赖: ```bash mvn clean install ``` 或者 ```bash gradle clean build ``` ### 示例代码:使用 SourceContext.collect 的简单流处理程序 ```java public class CustomSourceExample { public static void main(String[] args) throws Exception { final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.addSource(new RichParallelSourceFunction<String>() { private volatile boolean isRunning = true; @Override public void run(SourceContext<String> ctx) throws Exception { int count = 0; while (isRunning && count < 100) { ctx.collect("Message-" + count); count++; Thread.sleep(100); } } @Override public void cancel() { isRunning = false; } }).print(); env.execute("Custom Source Example"); } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangvalue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值