在hadoop中获取堆栈溢出错误

时间:2013-06-28 08:02:49

标签: hadoop

使用java代码访问haddop文件时出现堆栈溢出错误。

import java.io.InputStream;
import java.net.URL;
import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;
public class URLCat 
{
    static 
    {
            URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }

    public static void main(String[] args) throws Exception 
    {
        InputStream in = null;
        try 
        {
            in = new URL(args[0]).openStream();
            IOUtils.copyBytes(in, System.out, 4096, false);
        }
        finally 
        {
            IOUtils.closeStream(in);
        }
    }
}

我使用eclipse来调试这段代码,然后我开始知道行

in = new URL(args[0]).openStream();

产生错误。

我通过传递hadoop文件路径来运行此代码,即

 hdfs://localhost/user/jay/abc.txt

例外(摘自评论):

Exception in thread "main" java.lang.StackOverflowError
  at java.nio.Buffer.<init>(Buffer.java:174) 
  at java.nio.ByteBuffer.<init>(ByteBuffer.java:259) 
  at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:52) 
  at java.nio.ByteBuffer.wrap(ByteBuffer.java:350) 
  at java.nio.ByteBuffer.wrap(ByteBuffer.java:373) 
  at java.lang.StringCoding$StringEncoder.encode(StringCoding.java:237) 
  at java.lang.StringCoding.encode(StringCoding.java:272) 
  at java.lang.String.getBytes(String.java:946) 
  at java.io.UnixFileSystem.getBooleanAttributes0(Native Method) 
  .. stack trace truncated ..

2 个答案:

答案 0 :(得分:3)

1)这是因为hadoop提供的FSURLStreamHandlerFactory类中的错误。请注意,该错误已在最新的包含此类的jar中修复。

2)此文件位于hadoop-common-2.0.0-cdh4.2.1.jar中。要完全理解这个问题,我们必须了解java.net.URL类的工作原理。

URL对象的工作

当我们使用其任何一个构造函数创建一个新URL而不传递“URLStreamHandler”时(通过为其值传递null或调用不使用URLStreamHandler对象作为其参数的构造函数),然后在内部调用一个名为getURLStreamHandler的方法( )。此方法返回URLStreamHandler对象并设置成员

URL类中的

变量。

此对象知道如何构建特定方案的连接,如“http”,“file”......等等。此URLStreamHandler由名为

的工厂构造

URLStreamHandlerFactory。

3)在上面给出的问题示例中,通过调用以下静态方法将URLStreamHandlerFactory设置为“FsUrlStreamHandlerFactory”。

    URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());

因此,当我们创建一个新URL时,此“FSUrlStreamHandlerFactory”用于通过调用其createURLStreamHandler(协议)方法为此新URL创建URLStreamHandler对象。

此方法inturn调用FileSystem类的loadFileSystems()方法。 loadFileSystems()方法调用ServiceLoader.load(“FileSystem.class”),因此它尝试通过搜索类路径中所有jar文件的所有META-INF / services / *。FileSystem文件来读取FileSystem实现类的二进制名称。阅读其条目。

4)请记住,每个jar都作为URL对象处理,这意味着每个jar都由ClassLoader在内部创建一个URL对象。类加载器提供URLStreamHandler对象

在构造这些jar的URL时,这些URL不会受到我们设置的“FSUrlStreamHandlerFactory”的影响,因为URL已经具有“URLStreamHandler”。因为我们是

处理jar文件时,类加载器设置“URLStreamHandler”,类型为“sun.net.www.protocol.jar.Handler”。

5)现在为了读取文件系统实现类的jar文件中的条目,“sun.net.www.protocol.jar.Handler”需要通过

构建每个条目的URL对象

调用不带URLStreamHandler对象的URL构造函数。由于我们已经将URLStreamHandlerFactory定义为“FSUrlStreamHandlerFactory”,因此它调用了createURLStreamHandler

(协议)方法导致无限地递归并导致“StackOverflowException”。

这个错误被Hadoop提交者称为“HADOOP-9041”。链接为https://issues.apache.org/jira/browse/HADOOP-9041

我知道这有点复杂。

简而言之,下面给出了解决这个问题的方法。

1)使用最新的jar hadoop-common-2.0.0-cdh4.2.1.jar,它修复了这个bug

2)在设置URLStreamHandlerFactory之前,将以下语句放在静态块中。

      static {
               FileSystem.getFileSystemClass("file",new Configuration()); 
               URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
             } 

请注意,静态块中的第一个语句现在不依赖于FsUrlStreamHandlerFactory,并使用file://的默认处理程序来读取META-INF / services / * .FileSystem文件中的文件。

答案 1 :(得分:1)

我有一个 解决方法。

如果更熟悉Hadoop世界(2014年1月)当前状态的人会启发我们和/或解释行为,那就太棒了。

我在尝试从Haddop运行URLCat时遇到了相同的StackOverflowError The Definitive Guide第三版Tom White

我遇到了Cloudera QuickStart 4.4.0和4.3.0的问题

同时使用jdk1.6.0_32和jdk1.6.0_45

在java.net.URL下面的org.apache.hadoop.fs.FileSystem初始化/类加载期间出现此问题 有一种递归异常处理正在进行中。 我尽我所能追查它。 该路径指向java.util.ServiceLoader,然后调用sun.misc.CompoundEnumeration.nextElement() 不幸的是,sun.misc.CompoundEnumeration的源代码是而不是包含在jdk src.zip中......也许是一种疏忽,因为它在java包中是sun.misc

在尝试通过另一个执行路径触发错误时,我想出了一个解决方法......

通过在注册StreamHandlerFactory之前调用org.apache.hadoop.fs.FileSystem.getFileSystemClass(String,Configuration),可以避免导致StackOverflowError的条件。

这可以通过修改静态初始化块来完成(参见上面的原始列表):

   static {
        Configuration conf = new Configuration();
        try {
            FileSystem.getFileSystemClass("file", conf);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        };
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }

这也可以通过将此静态块的内容移动到main()来实现。

我从2011年8月stackoverflow with FsUrlStreamHandlerFactory

发现了另一个对此错误的引用

我很困惑,更多的hadoop新手没有偶然发现这个问题...购买Hadoop书...下载Cloudera QuickStart ...尝试一个非常简单的例子...... FAIL!?

来自更有经验的人的任何见解将不胜感激。