假设我有这个数组列表['a','b','xx']。 我想提取每2个字符串组合(每2个元素)。例如['a','b'] ['a','xx'] ['b','a'] ['b','xx'] ['xx','a'] ['xx ','b']。
我已经编写了这段代码,但是当数组变得非常大时(10k for 例如,GC耗尽内存。
private Text empty = new Text("");
public void start(Iterable<Text> values,Context context) throws {
List<String> sitesArr = new ArrayList<String>();
HashMap<String, String> hmapPairs = new HashMap<String, String>();
for (Text site : values){
sitesArr.add(site.toString());
}
insertPairsToHash(hmapPairs, sitesArr);
writeContextFromHash(hmapPairs, context);
}
private void insertPairsToHash(HashMap<String, String> hmapPairs, List<String> sitesArr) {
for (int i=0; i<sitesArr.size(); i++) {
for (int j=i+1; j<sitesArr.size(); j++) {
String firstPair = sitesArr.get(i) + "_" + sitesArr.get(j);
String secondPair = sitesArr.get(j) + "_" + sitesArr.get(i);
hmapPairs.put(firstPair,secondPair);
}
}
}
private void writeContextFromHash(HashMap<String, String> hmapPairs, Context context) throws IOException, InterruptedException {
Text textTowriteToFile = new Text("");
for(Map.Entry<String, String> entry : hmapPairs.entrySet()) {
textTowriteToFile.set(entry.getKey());
context.write(textTowriteToFile, empty);
textTowriteToFile.set(entry.getValue());
context.write(textTowriteToFile, empty);
}
}
我使用2 for循环,在每次迭代中我插入2个组合(['a','b']和['b','a']第一个元素是键,第二个是值,所以在[哈希表示'a','b']'a'将是键,'b'将是值,反之亦然)。 然后我在哈希上迭代一次以发送值。 如何在使用更少内存的同时加快速度?
答案 0 :(得分:0)
为什么不直接在嵌套的for循环中调用“writeContextFromHash”而不创建HashMap?
答案 1 :(得分:0)
您应该在问题中添加更多信息。但基本上使用这种程序,随着输入变大,你总会遇到内存问题。使用10k条目,您最终会得到大约100米的组合,从而产生50米的地图条目。与数据结构的大小相乘(取决于您的输入),这会占用大量内存。 如果你事先知道输入的粗略大小,你可能只需为你的jvm分配足够的内存(除非你的机器很小)。如果这不能解决问题,则无法将所有结果保留在内存中。换出磁盘或按照上面的建议将结果直接写入控制台,而不是将它们保存在内存中。
答案 2 :(得分:0)
您可以简单地重构您的课程流式搜索结果。所以你不要保留组合元素的整个结果列表。
private Text empty = new Text("");
public void start(Iterable<Text> values,Context context) throws IOException, InterruptedException {
List<String> sitesArr = new ArrayList<String>();
for (Text site : values){
sitesArr.add(site.toString());
}
insertPairsToHash(sitesArr,context);
}
private void insertPairsToHash(List<String> sitesArr, Context context) {
for (int i=0; i<sitesArr.size(); i++) {
for (int j=i+1; j<sitesArr.size(); j++) {
String firstPair = sitesArr.get(i) + "_" + sitesArr.get(j);
String secondPair = sitesArr.get(j) + "_" + sitesArr.get(i);
doWrite(context, firstPair, secondPair);
}
}
}
private void doWrite(Context context, String firstPair, String secondPair) {
Text textTowriteToFile = new Text("");
textTowriteToFile.set(firstPair);
context.write(textTowriteToFile, empty);
textTowriteToFile.set(secondPair);
context.write(textTowriteToFile, empty);
}
这会降低你的内存使用量。
一般情况下,如果您的输入很大或没有限制,您会尝试流式传输结果,流式传输会增加一些复杂性,但会使内存使用量与您输入的大小无关。
您可以通过从列表中删除已删除的元素来删除它们。 在这种情况下,您应该使用LinkedList而不是ArrayList,因为从数组列表中删除head元素将涉及更多的GC和CPU时间,而不是链接列表中的相同操作。
然而,这不会降低峰值内存使用量,只会降低使用时间(随着进程的进行,您将需要更少的内存)。
如果其他组件在进程过程中消耗更多内存,它仍然可能有用。
List<String> sitesArr = new LinkedList<>();
private void insertPairsToHash(List<String> sitesArr, Context context) {
while (!sitesArr.isEmpty()) {
String left = sitesArr.remove(0);
for (String right : sitesArr) {
String firstPair = left + "_" + right;
String secondPair = right + "_" + left;
doWrite(context, firstPair, secondPair);
}
}
}