使用-Xmx32m Java命令在3个文件中最大的单词出现

问题描述

我需要开发一个应用程序,以检索出现在3个文件txt中的单词出现次数最多的应用程序,请注意,所有单词在这文件中的升序排列,并且某些单词可以出现在多个文件中。要运行该应用程序,我们将使用-Xmx32m命令(使最大堆大小为32MB),如下所示:

java -Xmx32m greatNrOccurrencies

我已经使用哈希映射和链接列表完成了应用程序,但是一旦我尝试使用命令-Xmx32m,应用程序就会发出内存不足错误。如果有人可以提供任何想法,我将不胜感激。

您可以在下面找到代码

package topkwordsocurrences;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.*;

public class TopKWordOcurrences {

    public static void getKWordOcurrences() {
        Scanner firstReader,secondReader,thirdReader;
        Map<String,Integer> uniqueWords = new LinkedHashMap<>();
        String line;
        try {
            PrintWriter out = new PrintWriter(".\\src\\topkwordsocurrences\\out.txt");
            firstReader = new Scanner(new FileReader(".\\src\\topkwordsocurrences\\f1.txt"));
            secondReader = new Scanner(new FileReader(".\\src\\topkwordsocurrences\\f2.txt"));
            thirdReader = new Scanner(new FileReader(".\\src\\topkwordsocurrences\\f3.txt"));

            while (firstReader.hasNextLine()) {
                line = firstReader.nextLine();
                
                if (uniqueWords.containsKey(line)) {
                    // if your keys is already in map,increment count of it
                    uniqueWords.put(line,uniqueWords.getorDefault(line,0) + 1);
                } else {
                    // if it isn't in it,add it
                    uniqueWords.put(line,1);
                }
               
            }


            while (secondReader.hasNextLine()) {
                line = secondReader.nextLine();
                
                if (uniqueWords.containsKey(line)) {
                    // if your keys is already in map,1);
                }
        }

            while (thirdReader.hasNextLine()) {
                line = thirdReader.nextLine();
                if (uniqueWords.containsKey(line)) {
                    // if your keys is already in map,1);
                }
            }

            //convert HashMap into List
            List<Map.Entry<String,Integer>> list = new ArrayList<>(uniqueWords.entrySet());
            //sorting the list elements in descending order // to make ascending order alter return o1.getValue().compareto(o2.getValue());
            Collections.sort(list,new Comparator<Map.Entry<String,Integer>>() {
                public int compare(Map.Entry<String,Integer> o1,Map.Entry<String,Integer> o2) {
                    return o2.getValue().compareto(o1.getValue());
                }
            });


            List<Map.Entry<String,Integer>> top5 = list.subList(0,5);

            for (Map.Entry<String,Integer> i : top5) {
                System.out.println(i.getKey());
            }
            
        } catch (FileNotFoundException e) {
            e.printstacktrace();
        }
    }

    public static void main(String[] args) {
        getKWordOcurrences();
    }

}

解决方法

您可以采取几种措施来减少程序的内存消耗。

首先,您可以在阅读每个文件后将其关闭。您当前打开了3个阅读器,在程序结束之前不要关闭它们。您可以做得更好:

String[] fileNames = new String[]{
        ".\\src\\topkwordsocurrences\\f1.txt",".\\src\\topkwordsocurrences\\f2.txt",".\\src\\topkwordsocurrences\\f3.txt"
};
 
for (String fileName : fileNames) {
    try (Scanner s = new Scanner(new FileReader(fileName))) {
        while (s.hasNextLine()) {
            processWord(s.nextLine());
        }
    } // file is closed when this line is reached,even if exceptions thrown
}

请注意,上述方法也消除了很多重复:您只需实现processWord或一次打开文件的逻辑即可。

您使用LinkedHashmap来存储单词。您的文件中有多少个独特的单词?如果是普通文本,则保持在低内存限制内应该没有问题。但是,如果单词是机器生成的,则无法选择映射来将所有单词存储在内存中。在这两者之间,其他类型的地图实现可能需要较少的内存-例如,HashMap尽管不保留顺序,但每个条目所需的空间却比LinkedHashmap少。使用Scanner也会产生开销(并且要以较小的内存成本执行预读以提高性能)。如果迫切需要记忆,可以直接使用阅读器

如果您有很多不同的单词,尽管进行了这些更改,但内存用完了,您可以完全避免使用哈希表:您只在寻找最频繁的单词-或K最-频繁的单词,因此仅存储前K个单词及其频率就足够了。

使用伪代码:

open all scanners
for each scanner,count all occurrences of its 1st word
until all scanners are empty:
   sort last-read-words from scanners
   merge counts for the lexicographically smallest word (if found in several scanners)
   check to see if smallest word should enter into top-k list
   for each scanner which had smallest word,count occurrences for its next word