IT序号网

java之庞大的 Json 解析器

lvdongjie 2024年11月01日 编程语言 37 0

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

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

如您所见,我还有剩余内存。是否因为 CPU 而发生此错误?

更新: Json 表示来自 Free Code Camp 的数据:https://medium.freecodecamp.com/free-code-camp-christmas-special-giving-the-gift-of-data-6ecbf0313d62#.7mjj6abbg

数据看起来像这样:

[ { “名称”:“Waypoint:向 HTML 元素问好”, “完成日期”: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(); 
    } 

请您参考如下方法:

解析 JSON(或任何东西,就此而言)不会占用与原始文件大小相同的内存。

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

尽管如此,一个对象比字符串需要更多的内存来表示。如果您有一个数组,它可能会被解析为一个列表,那么该列表就会有开销。将该开销乘以您在 JSON 中拥有的实例(相当多,在一个 3.6 GB 的文件中),您最终得到的东西占用的内存远远超过 3.6GB。

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

希望对您有所帮助。


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!