巨大的Json Parser

时间:2016-05-02 07:03:38

标签: java json

我有这个自定义解析器,用Java制作,我想将一个3,6 GB的Json导出到一个Sql Oracle数据库中。导入工作正常,样本Json为8MB。但是当我尝试解析整个3,6 GB JSON时会出现一些内存问题,即java.lang.OutOfMemoryError

我使用-Xmx5000m为此分配5 GB内存。我的笔记本电脑有足够的内存。

Resource usage

Error message

你可以看到我留下了记忆。这个错误是否因为CPU而发生?

更新: Json代表免费代码营的数据:https://medium.freecodecamp.com/free-code-camp-christmas-special-giving-the-gift-of-data-6ecbf0313d62#.7mjj6abbg

数据如下所示:

[   {     “name”:“Waypoint:向HTML Elements问好”,     “completedDate”:1445854025698,     “解决方案”:“

Hello World

\ n”   } ]

正如我所说,我已经尝试使用8MB样本Json进行解析,并使用相同的数据并且它可以工作。那么代码真的是问题吗?

这是一些代码

enter code here
public class MainParser {

public static void main(String[] args) {
    //Date time;
    try {
        BufferedReader br = new BufferedReader(
                new FileReader("output.json")); //destination to json here
        Gson gson = new Gson();
        Type collectionType = new TypeToken<List<List<Tasks>>>() {
        }.getType();
        List<List<Tasks>> details = gson.fromJson(br, collectionType);

        DBConnect connection = new DBConnect("STUDENT","student");
        connection.connect();

    for (int person=0;person<details.size();person++)
    {

        for (int task = 0; task < details.get(person).size(); task++)
        {
            connection.insert_query(person + 1,
                    task + 1,
                    details.get(person).get(task).getName(),
                     (details.get(person).get(task).getCompletedDate()/1000),
                    details.get(person).get(task).getSolution());
        }
    }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
}

这是insert_query方法:

enter code here
public void insert_query(int person_id, int task_id, String taskName, double       date, String solution) throws SQLException {


           Statement stmt = conn.createStatement();
    try {
        String query = "INSERT INTO FreeCodeCamp VALUES(?,?,?,?,?)";
        PreparedStatement ps = conn.prepareStatement(query);
        ps.setInt(1,person_id);
        ps.setInt(2,task_id);
        ps.setString(3,taskName);
        ps.setDate(4,null);
        ps.setString(5,solution);
        /*stmt.executeUpdate("INSERT INTO FreeCodeCamp VALUES("
                + person_id + ","
                + task_id + ","
                + "'" + taskName + "',"
                + "TO_TIMESTAMP(unix_ts_to_date(" + date + "),'YYYY-MM-DD HH24:MI:SS'),"
                + "'" + solution + "')");
        stmt.close();*/
        ps.execute();
        ps.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }

3 个答案:

答案 0 :(得分:4)

解析JSON(或其他任何内容)不会占用原始文件大小的相同内存。

表示对象的每个JSON字符串块将成为一个对象,将ADDING内存添加到已加载的JSON中。如果你使用某种流解析它,你仍然会添加内存但更少(你不会在内存中保存整个3.6GB文件)。

但是,对象占用的内存比字符串多。如果您有一个可能被解析为列表的数组,那么该列表就会产生开销。将你在JSON中的实例的开销乘以(相当多,在一个3.6 GB的文件中),你最终得到的内存不仅仅是3.6GB。

但是如果你想把它解析成一个流,然后处理每个记录,然后丢弃它,你就可以做到。在使用流的两种情况下,您都需要一个解析JSON的组件,并让您处理每个已解析的对象。如果您知道结构,那么自己编写结构可能会更容易。

希望它有所帮助。

答案 1 :(得分:2)

您需要使用基于事件的/流式JSON解析器。我们的想法是,解析器不会一次解析整个JSON文件并将其保存在内存中,而是发出&#34; events&#34;在每个重要的句法单元的开头和结尾。然后编写代码来处理这些事件,额外并汇编信息,并(在您的情况下)将相应的记录插入数据库。

以下是一些开始阅读Oracle流媒体JSON API的地方:

以下是GSON等效文档的链接:

答案 2 :(得分:1)

请参阅Gson's Streaming doc

当整个模型无法加载到内存中时使用