- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个包含大约 12,000 个键/值对的序列文件。最大值为 143MB,其他均小于 1MB。 mapred.child.java.opts
设置为 -Xmx500m
.我得到一个 Error: Java heap space
在处理这个文件时。这是我的映射器:
public class MyMapper extends Mapper<Text, BytesWritable, Text, Text> {
@Override
protected void setup(Context context) throws IOException, InterruptedException {
super.setup(context);
}
@Override
protected void map(Text key, BytesWritable value, Context context) throws IOException, InterruptedException {
Configuration conf = context.getConfiguration();
String content = new String(value.getBytes());
// remove HTML tags (content is a HTML document)
String content_no_html = Jsoup.parse(content).text();
// try to find a regex match
}
}
}
我认为这可能是因为我的 Map 类正在将值从 BytesWritable 转换为 String,然后处理该字符串。但是我试图只在映射器中处理一个键/值对,如果 value.getLength() < 8388608
(8 MB),内存仍然不足。
我可以增加 -Xmx500m
,但我担心这不会解决我的问题,因为我有几千个序列文件需要处理而且我不知道最大的键/值对有多大(我对大的不感兴趣键/值对,因此是上面的 8MB 限制)。作为记录,我尝试了一些序列文件,导致 ~2500 个映射步骤,并且错误发生在第一个 1990 年左右成功之后,这让我认为单个键/值对大小是这里的问题.
有没有办法只将键/值对传递给 Mapper 达到大小限制?为什么我什至得到 Error: Java heap space
首先?
我尝试按照建议创建一个自定义的SequenceFileInputFormat,发现在调用map函数之前出现了Heap space error。准确地说,SequenceFileRecordReaders nextKeyValue()
是导致错误的原因。我通过运行一个什么都不做的 map 函数仔细检查了这一点,但它仍然崩溃了。我找不到修复那里错误的方法,所以我想增加内存是我在这里唯一的机会。
最佳答案
8 MB 的 HTML 仍然太大了!
例如,假设您的 8 MB html 文本是一个包含 80 字节长元素的 ul 列表,您将有 1,000,000 个元素:
<ul>
<li class="item" data-index="000000">This is the <b>first</b> line.</li>
<li class="item" data-index="000001">This is the <b>second</b> line.</li>
[...]
<li class="item" data-index="999999">This is the <b>last</b> line.</li>
</ul>
Jsoup Element
每个 li 元素的类(它是 Node
的子类)具有以下结构,我们可以从中估计(理论上和近似地)我示例的 html 列表的内存占用量:
LinkedHashMap<String, Attribute>
有 1 个条目(48 字节)
所以链表的单个元素占用的内存在580字节左右。
这 1,000,000 个元素使用的总内存约为 580 MB。
此外,主要的 ul 元素在其 childrenNodes 字段中包含对那些 li 元素的 1,000,000 个引用的列表,因此它需要 8 MB 的内存。
最后,当调用 text()
如果删除标签后留下的文本对应于 5MB 的序列化字符,那么您需要 String
500万char
s,占用 5,000,000*2 = 10 MB。
因此,如果您的 html 就像我显示的列表一样,那么您需要在对 map()
的单次调用期间存储在堆中。功能:
new String(value.getBytes())
=> ~ 16MBJsoup.parse(content)
=> ~ 590 MB.text()
=> ~ 10MB难怪你会得到一个只有 500 MB 的堆的 java 堆空间错误!
“内存爆炸”发生在用JSoup解析文件时,因为它要创建很多对象,而java对象,尤其是Strings,是很重的。
这完全取决于您的 html 的外观。如果您的 html 具有与我的示例大致相同的 html 标签/属性浓度,我认为您可以将阈值定义为 2 MB 左右以确保安全。
如果value.getLength() < 2_000_000
可以一开始就退出map函数和你一样。或者,如果不浪费数据对您来说很重要,您可以做一些更有趣的事情,比如运行正则表达式来计算 content
中标签或属性的数量。字符串。如果您有 20 MB 的文本,但其中只有 1 个标签,它仍然适合内存,无需跳过它。
关于java - Hadoop 序列文件 : process key/value only up to a certain size?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38081654/
我是一名优秀的程序员,十分优秀!