简单Java代码上的大内存占用

时间:2015-12-05 20:35:02

标签: java performance memory optimization memory-management

我正在spoj解决问题,系统显示我的程序占用了1341M内存。当我查看其他语言的提交时,他们需要~3M,这要少约400倍!

我的代码如下:

class Main {
    static List<BigInteger> numbers = new ArrayList<>();

    static {
        BigInteger max = BigInteger.TEN.pow(100);

        numbers.add(BigInteger.ONE);
        numbers.add(BigInteger.valueOf(2l));
        BigInteger last = numbers.get(1);

        while (last.compareTo(max) <= 0) {
            numbers.add(numbers.get(numbers.size() - 1).add(numbers.get(numbers.size() - 2)));
            last = numbers.get(numbers.size() - 1);
        }
    }

    public static void main(String[] args) throws java.lang.Exception {
        BufferedReader bi = new BufferedReader(new InputStreamReader(System.in));
        String line;
        String delims = " ";
        while ((line = bi.readLine()) != null) {
            StringTokenizer tokenizer = new StringTokenizer(line, delims);
            BigInteger from = new BigInteger(tokenizer.nextToken());
            BigInteger to = new BigInteger(tokenizer.nextToken());

            if (from.equals(BigInteger.ZERO) && to.equals(BigInteger.ZERO)) {
                return;
            } else {
                System.out.println(countInRange(from, to));
            }
        }
    }

    public static int countInRange(BigInteger from, BigInteger to) {
        int fromIndex = Collections.binarySearch(numbers, from);
        fromIndex = fromIndex < 0 ? Math.abs(fromIndex) - 1 : fromIndex;
        int toIndex = Collections.binarySearch(numbers, to);
        toIndex = toIndex < 0 ? Math.abs(toIndex) - 1 : toIndex + 1;
        return toIndex - fromIndex;
    }
}

我认为BufferedReader是高内存消耗的原因。在这种情况下,是否有可能显着改善内存占用?我不是在谈论实现3M,而是至少在100M左右。

2 个答案:

答案 0 :(得分:1)

首先关闭:您如何保留numbers中的元素?可能会有一些,因为你的最大值是10 pow 100。

第二:考虑Java内存模型。 1341M大约适合32位Java VM。所以也许只是你在堆上生成对象(所有这些闪亮的new BigInteger),Java产生了大量的垃圾内存。但是,如果您没有为您的流程设置正确的选项,则不会将其返回给操作系统。

您是否尝试运行只有100M内存的程序(通过在java调用中设置-Xmx100m选项?

考虑创建一个堆转储并检查一下(我建议Eclipse Memory Profiler看看你的记忆是什么。我最好的猜测是:它是大量预先计算的数字(它们是什么) ?对我来说,似乎是一个卢卡斯序列?)或只是垃圾等待收集。

答案 1 :(得分:1)

快速检查:您确定IDE实际上没有使用1341MB内存(例如Eclipse或Netbeans)吗?

我将代码打包到一个可执行的Jar中,在具有64b Oracle JRE 1.8.0.66的Windows 7 x64机器上。运行代码时,系统仅显示大约10MB的内存消耗。我使用:

生成了一个堆转储
java -agentlib:hprof=file=snapshot.hprof,format=b -jar number_counter.jar

使用Eclipse Memory Analyzer进行分析时,使用过的对象的内存占用率非常低。

一些注意事项:

  • number 数组不应该很大。据我所知,它只包含一个生长得非常快的Fibonacci序列,因此我只看到了〜500个存储的BigNumbers。
  • 没有真正的理由说明为什么BufferedReader应该占用大量空间。这是一个使用频繁的对象,我确信已经投入了很多优化工作。

要结束,请检查您是否正在监控正确的Java进程,请确保使用最新的JRE并确保不使用某些不必要的内存管理规则。您的代码似乎很好,占用空间应小于20 MB。