java.lang.NoClassDefFoundError: Could not initialize class org.xerial.snappy.Snappy

在linux平台,spark读取hdfs上的parquet文件时,抛出的Snappy类不能初始化:

java.util.concurrent.ExecutionException: java.lang.NoClassDefFoundError:
    Could not initialize class org.xerial.snappy.Snappy
...
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.xerial.snappy.Snappy

刚开始以为类路径中没有Snappy的包,但是检查后,发现Snappy的相关依赖包都是有的。感觉有点见鬼了。
之后通过google(百度太垃圾)发现java的Snappy是通过java的jni实现的,在Snappy类使用时,会先执行一段静态代码块:

static {
        try {
            impl = SnappyLoader.load();
        }
        catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

通过SnappyLoader工具类的load()方法实例化SnappyNative类,SnappyNative类是所有方法都是native方法的类,该类的所有方法都通过jni实现,而Snappy类只是代理了SnappyNative而已。
在SnappyLoader类的load()方法调用中,会将Snappy包中自带的.o文件(该文件中是具体Snappy解压缩的实现,windows平台为.dll文件)拷贝到临时目录下,默认使用环境变量java.io.tmpdir的值(该值为/tmp),你也可以通过在jvm参数-Dorg.xerial.snappy.tempdir=/tmp/to/path设置自定义的临时目录,拷贝完成后会通过System.load()方法加载该.o文件。
接下来,该说一下我遇到的java.lang.NoClassDefFoundError: Could not initialize class org.xerial.snappy.Snappy异常的原因是/tmp目录没有可用空间了,所以当拷贝.o文件时,该文件大小为0,所以在执行Snappy的静态代码块中的代码是出错。

猜你喜欢

转载自blog.csdn.net/Shie_3/article/details/82595219