【问题标题】:Large memory footprint on simple Java code简单 Java 代码占用大量内存
【发布时间】:2016-03-10 16:43:23
【问题描述】:

我正在解决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左右。

【问题讨论】:

  • 要重现问题,了解程序的输入是必要的。

标签: java performance memory optimization memory-management


【解决方案1】:

首先:您在numbers 中保留了哪些元素?可能相当多,因为你的最大值是 10 pow 100。

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

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

考虑创建一个堆转储并检查它(我推荐 Eclipse Memory Profiler 看看是什么占用了你的内存。我现在最好的猜测是:它要么是大量的预先计算的数字(它们是什么?看起来像卢卡斯序列对我来说?)或者只是等待收集的垃圾。

【讨论】:

    【解决方案2】:

    快速检查:您确定您的 IDE(例如 Eclipse 或 Netbeans)实际上并未消耗 1341MB 内存吗?

    我将您的代码打包到一个可执行 Jar 中,在 Windows 7、x64 机器上使用 64b Oracle JRE 1.8.0.66。运行代码时,系统仅显示 ~10MB 内存消耗。我使用以下方法生成了一个堆转储:

    java -agentlib:hprof=file=snapshot.hprof,format=b -jar number_counter.jar
    

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

    一些注意事项:

    • number 数组不应该很大。据我了解,它只包含一个增长很快的斐波那契数列,因此我只看到了大约 500 个存储的 BigNumber。
    • BufferedReader 占用空间大并没有真正的原因。这是一个使用频率很高的对象,我确信已经在它上面投入了很好的优化工作。

    总结,请检查您是否正在监控正确的 java 进程,确保您使用的是最新的 JRE,并确保您没有使用一些不必要的内存管理规则。您的代码看起来不错,占用空间应该小于 20 MB。

    【讨论】:

      猜你喜欢
      • 2022-10-30
      • 2022-12-02
      • 2020-09-20
      • 2014-05-11
      • 2011-02-27
      • 2013-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多