JAVA内存限制超出问题

时间:2015-04-06 07:36:38

标签: java memory memory-management dynamic-programming

我编写了一个JAVA程序,它几乎不需要3-4 MB的内存,但仍然不知何故超过了我提交判断问题的分级器上的16 MB内存限制。

我有一个大小为2500 * 100的整数2D数组,占用大约1 MB,以及一个最多有2500个节点和2499个边(Tree)的邻接列表。

为什么它超过16 MB的内存限制?我知道JAVA有一些开销,但我仍然无法理解为什么它超出了限制。如果有人可以解释为什么代码消耗这么多内存的原因,那将对我有很大的帮助。我也在做DFS,它会消耗一些堆栈内存,但没有理由超过16 MB限制。

以下是代码:

import java.io.*;
import java.util.*;
class CateringContracts2pi
{
static ArrayList<ArrayList<Integer>> adj = new ArrayList<ArrayList<Integer>>(2505);
static int mod = 10243;
static int ans=0;
static int dp[][]=new int[2501][101];
static int temp[]=new int[101];
static int N,K;
public static void main(String[]args)
{
    Scanner sc = new Scanner(System.in);
    for(int i=0;i<2505;i++)
        adj.add(new ArrayList<Integer>());
    N = sc.nextInt();
    K = sc.nextInt();
    for(int i=1;i<N;i++)
    {
        int u = sc.nextInt();
        int v = sc.nextInt();
        adj.get(u).add(v);
        adj.get(v).add(u);
    }
    for(int i = 1; i <= N; i++)
    {
        dp[i][0] = dp[i][1] = 1;
    }
    dfs(1,0);
    System.out.println(ans);
}

static void dfs(int node,int par)
{
    int sz = adj.get(node).size();
    for(int i=0;i<sz;i++)
    {
        int next = adj.get(node).get(i);
        if(next==par)continue;
        dfs(next,node);
        Arrays.fill(temp,0);
        for(int j=1;j<=K;j++)
        {
            for(int k=1;k+j<=K;k++)
            {
                temp[j+k]+=dp[node][j]*dp[next][k] % mod;
            }
        }
        for(int j=1;j<=K;j++)
        {
            dp[node][j] += temp[j];
            dp[node][j] %= mod;
        }
    }
    ans+=dp[node][K];
    ans%=mod;
}

}

2 个答案:

答案 0 :(得分:0)

您手动输入了~2505个元素吗?我真的不羡慕你。我将您的示例修改为更友好的视图:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ThreadLocalRandom;

class CateringContracts2pi {
    private static final List<List<Integer>> adj = new ArrayList<>(2505);
    private static final int mod = 10243;
    private static final int dp[][] = new int[2501][101];
    private static final int temp[] = new int[101];
    private static int ans = 0;

    public static void main(String[] args) {
        long beforeUsedMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < 2505; i++) {
            adj.add(new ArrayList<>());
        }
        System.out.print("Enter N:");
        final int N = sc.nextInt();
        long afterUsedMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        long actualMemUsed = afterUsedMem - beforeUsedMem;
        System.out.println("usage = " + actualMemUsed / 1024);
        for (int i = 1; i < N; i++) {
            int u = ThreadLocalRandom.current().nextInt(0, N);
//            int u = sc.nextInt();
//            int v = sc.nextInt();
            int v = ThreadLocalRandom.current().nextInt(0, N);
            adj.get(u).add(v);
            adj.get(v).add(u);
        }
        actualMemUsed = afterUsedMem - beforeUsedMem;
        System.out.println("usage = " + actualMemUsed / 1024);
        for (int i = 1; i <= N; i++) {
            dp[i][0] = dp[i][1] = 1;
        }
        actualMemUsed = afterUsedMem - beforeUsedMem;
        System.out.println("usage = " + actualMemUsed / 1024);
        System.out.print("Enter K:");
        final int K = sc.nextInt();
        dfs(1, 0, K);
        System.out.println(ans);
        actualMemUsed = afterUsedMem - beforeUsedMem;
        System.out.println("usage = " + actualMemUsed / 1024);
    }

    private static void dfs(int node, int par, final int K) {
        int sz = adj.get(node).size();
        for (int i = 0; i < sz; i++) {
            int next = adj.get(node).get(i);
            if (next == par) continue;
            dfs(next, node, K);
            Arrays.fill(temp, 0);
            for (int j = 1; j <= K; j++) {
                for (int k = 1; k + j <= K; k++) {
                    temp[j + k] += dp[node][j] * dp[next][k] % mod;
                }
            }
            for (int j = 1; j <= K; j++) {
                dp[node][j] += temp[j];
                dp[node][j] %= mod;
            }
        }
        ans += dp[node][K];
        ans %= mod;
    }
}

我设置了-Xmx4m JVM设置并使用不同的输入参数运行它 - 我得到的所有内容都是java.lang.StackOverflowError。这个异常与内存使用没有任何关系,我的意思是堆内存。您可以通过-Xss参数设置堆栈大小,但我认为您需要重构您的dfs方法。

关于堆内存使用我们可以说些什么?我们来算一下:

  • dp [] [] = new int [2501] [101] =(2501 * 4 + 12)* 102 = 998Kb
  • temp [] = new int [101] = 101 * 4 + 12 = 416字节
  • Integers列表(2501 * 16 + 16)* 101 = 3,9Mb
  • 列表

因此,对于数据,我们有~5Mb(填充所有列表列表时的最大值),对于JVM,我们有1Mb。就是这样。

答案 1 :(得分:-1)

JVM本身设置了它将使用多少内存。以下提示可以为您提供帮助:How is the default java heap size determined?。您可以尝试使用-Xmx,-Xms等标志来减少已用内存量。