使用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 ..
答案 0 :(得分:3)
1)这是因为hadoop提供的FSURLStreamHandlerFactory类中的错误。请注意,该错误已在最新的包含此类的jar中修复。
2)此文件位于hadoop-common-2.0.0-cdh4.2.1.jar中。要完全理解这个问题,我们必须了解java.net.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!?
来自更有经验的人的任何见解将不胜感激。