1

作为我代码的一部分,我需要为具有 70k 顶点和 700k 边的图计算一些中心性度​​量。为此,我使用了数组和哈希映射数据结构。不幸的是,我在程序中间耗尽了内存。处理这种情况的最佳 JVM 热点参数是什么?这是我得到的例外:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.HashMap.createEntry(Unknown Source)
    at java.util.HashMap.addEntry(Unknown Source)
    at java.util.HashMap.put(Unknown Source)

所以我用 -Xmx6g 改变了堆大小,但是这个参数没有解决问题。我仍然对堆空间有同样的问题。

在我的程序中,我想为每个节点计算一些度量值,不幸的是 JVM 保留所有节点的信息并尝试为每个节点计算它。我想知道有什么方法可以改变 JVM 以从内存中删除不需要的信息?例如,我的代码在从 70000 个节点计算 1000 个节点的度量后崩溃。无论如何在计算后从内存中删除与这 1000 个节点相关的信息?内存可以通过这种方式分配给其他节点。这与垃圾收集器有关吗? 这是我的代码(使用 JUNG 库)

public class FindMostCentralNodes {
    private DirectedSparseGraph<Customer, Transaction> network = new DirectedSparseGraph<Customer, Transaction>();
    static String dbName="SNfinal";
    private int numberofNodes=0;
    public static void main(String[] args) throws NumberFormatException, SQLException {
        FindMostCentralNodes f=new FindMostCentralNodes();
        int counter=1;
        DirectedSparseGraph<Customer, Transaction> tsn=f.getTSN();
        DistanceCentralityScorer<Customer,Transaction> scorer=new DistanceCentralityScorer<Customer,Transaction>(tsn,false,true,true);// un-weighted
        Collection<Customer> subscribers=tsn.getVertices();

        for(Customer node:subscribers){
            String sql="update Node set dist_centrality='"+scorer.getVertexScore(node)+"' where subscriber='"+node.getName()+"'";
            DatabaseManager.executeUpdate(sql,dbName);
            System.out.println("Update node centrality measures successfully!: "+counter++);
            node=null;
        }
    }
    public DirectedSparseGraph<Customer,Transaction> getTSN() throws NumberFormatException, SQLException{
        network= new DirectedSparseGraph<Customer,Transaction>();
        String count="select count(*) as counter from Node";
        ResultSet rscount=DatabaseManager.executeQuery(count, dbName);
        if(rscount.next()) {
            numberofNodes=rscount.getInt("counter");
        }
        Customer [] subscribers=new Customer[numberofNodes];
        String sql="select * from Node"; 
        ResultSet rs=DatabaseManager.executeQuery(sql, dbName);
        while(rs.next()){
            Customer sub=new Customer();
            sub.setName(rs.getString("subscriber"));
            network.addVertex(sub);
            subscribers[rs.getInt("nodeID")-1]=sub;
            sub=null;
        }
        String sql2="select * from TSN";
        ResultSet rs2=DatabaseManager.executeQuery(sql2, dbName);
        while(rs2.next()){
            Transaction transaction=new Transaction(Double.parseDouble(rs2.getString("weight")));
            network.addEdge( transaction, subscribers[rs2.getInt("callerNID")-1], subscribers[rs2.getInt("calleeNID")-1] );
            transaction=null;

        }
        //garbage
        rscount=null;
        rs=null;
        rs2=null;
        subscribers=null;
        return network;
    }


}
4

3 回答 3

1

垃圾收集器将从程序中的活动变量中删除不再可访问的任何对象。它会在放弃并抛出OutOfMemoryError. 如果您认为内存中保留了太多对象,那么首先要做的就是放弃任何您不需要的对象,这样它们就不再可以访问了。由于您没有向我们展示任何代码,因此我们无法建议您做出任何具体的更改。

如果您修剪了不必要的对象,但仍然没有足够的内存,您可以研究使用更紧凑的方式来存储数据。一个关键技术是使用堆外存储。这比简单地使用对象需要更多的工作,但如果正确完成,在空间和 CPU 方面都可以更有效。看:

于 2013-08-12T08:26:35.087 回答
0

我通过创建一个每次处理 500 个节点的整个算法的方法来解决这个问题。每次运行此方法后,GC 现在可以删除整个变量,这样我的问题就解决了。

于 2013-08-14T08:50:32.547 回答
0
  • 尝试更改堆大小 (-Xmx) 参数
  • 如果您不使用 HashMap 中的某些项目,请使用 HashMap.remove 方法。如果没有更多对这些对象的引用,它们将被 GC 收集。
  • 使用 Trove 收藏:http ://trove.starlight-systems.com/overview
于 2013-08-12T07:38:18.040 回答