Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多个线程尝试从数据库获取数据时超出了GC开销限制_Java_Multithreading_Garbage Collection - Fatal编程技术网

Java 多个线程尝试从数据库获取数据时超出了GC开销限制

Java 多个线程尝试从数据库获取数据时超出了GC开销限制,java,multithreading,garbage-collection,Java,Multithreading,Garbage Collection,我有一个表,其中有近700万个数据,将来还会变得更大!我尝试使用多个线程获取数据。我的方法是以分页方式获取数据,并将每一页交给一个线程。换句话说,在14页内获取数据。每个数据库都有500000个数据。因此创建了14个线程 像这样: public Response determineOwnership(){ ZonedDateTime from = ZonedDateTime.now(); int NUM_OF_THREADS = 14; try {

我有一个表,其中有近700万个数据,将来还会变得更大!我尝试使用多个线程获取数据。我的方法是以分页方式获取数据,并将每一页交给一个线程。换句话说,在14页内获取数据。每个数据库都有500000个数据。因此创建了14个线程

像这样:

public Response determineOwnership(){
        ZonedDateTime from = ZonedDateTime.now();
        int NUM_OF_THREADS = 14;
        try {
            List<Future<List<String[]>>> futures = new ArrayList<>(0);
            ThreadPoolExecutor executor = (ThreadPoolExecutor)               
            Executors.newFixedThreadPool(NUM_OF_THREADS);
            for (int i = 500000; i <= 7000000; i = i + 500000) {
                String query = "SELECT * from (SELECT u.usr_mobile,u.national_code,rownum r from usr_mobile_verification u) where r > " + (i - 500000) + " and r <= " + i;
                JdbcMTSample callable = new JdbcMTSample(query);
                Future<List<String[]>> result = executor.submit(callable);
                futures.add(result);
            }
            executor.shutdown();
//these are the next steps to be done. get the futures and merge them into a big list and ... .it blows before arriving here
            for (Future f : futures) {
                try {
                    f.get();
                } catch (Exception ex) {
                    return ResponseHelper.serverError();
                }
            }
            ZonedDateTime to = ZonedDateTime.now();
            return ResponseHelper.ok("took " + Duration.between(from, to).toMinutes() + " Minutes");
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseHelper.serverError();
        }
}

请注意,如果我不返回列表,而是返回void,那么所有线程都将完成它们的工作,一切都将正常。但我需要在最后返回列表,因为我将在下一个级别对其进行一些操作。我应该如何在最后返回列表并将它们合并到最终列表中

附言:我将堆大小增加了
-Xms1g-Xmx2g
。此外,我不能只查询数据库,并以正常的方式获得结果列表,因为这需要太多的时间,并将导致内存不足

            -------------------UPDATE-----------------------
为了消除内存不足异常,我决定不在任何变量中存储任何内容。因为最后我需要更新表中的一列,而不需要返回任何内容。因此,我编辑了
jdbcmsample
class。但这也需要太多的时间。即使增加线程数也会产生更糟糕的效果。对此,我应该怎么做?

“超出GC开销限制”是垃圾回收器在垃圾回收周期内找不到足够的内存释放而导致的
OutOfMemoryError
的一种变体。您可以查看以了解如何进一步调试问题,并了解哪些对象正在占用内存

这种情况可以通过两种方式解决:

  • 改进算法逻辑以分配更少的对象

  • 不断增加JVM堆(
    -Xmx
    ),直到有足够的内存用于当前的算法逻辑


  • 该错误表示JVM正在耗尽内存,即使用的内存超过了它所拥有的内存

    获取表中的所有数据,然后循环遍历每个数据,并将移动电话和国家代码作为远程rest服务的输入,并根据该数据更新该表中的一列。这就是工作

    幸运的是,此任务不需要同时将整个表存储在内存中。与加载所有行,然后执行所有API请求,然后将所有内容写回db不同,您可以加载一些行,执行一些请求,然后将其写回db,并重复此操作直到完成。这样,只需要同时在内存中存储一些行,而不是所有行


    这通常是在SpringBatch等框架的帮助下完成的。这还提供了您可能需要的其他功能,例如恢复已中断的更新的功能。

    您是否已尝试使用-XX:-UseGCOverdeLimit禁用限制您到底想做什么?将
    NATIONAL_code
    USR_MOBILE
    读取到Java堆内存中,以存储所有7百万条数据库记录?在这里,拥有更多线程对您没有帮助,即使您拥有更多线程,堆内存仍然是相同的。@KarolDowbecki这是我的问题。那我该怎么办?我使用线程来加速抓取操作。@ChrisMaggiulli是的,但它没有帮助您选择了一种最低效的方式来表示内存中的行数据,即字符串数组。与拥有
    long
    int
    的专用对象相比,您很容易消耗的内存是所需内存的十倍以上。尽管如此,这将消耗大约1GB的内存,并且仍然适合您的堆内存。但JDBC驱动程序本身存在未知且无法控制的开销。跟着做,不要把所有的东西都记在记忆里。当I/O带宽成为实际瓶颈时,使用更少的线程。试试新的JDK。不要认为增加
    -Xmx
    会有帮助。最高限额是多少?@reza-增加
    -Xmx
    可能有助于。。。如果您有足够的RAM使堆足够大。但如果选项1是可以实现的,这是一个浪费的解决方案。请使用上面提到的@meriton的Spring批处理。我已经附上下面的例子来处理巨大的问题volume@Rakesh我不能使用spring库,因为我正在使用jakarta ee,不能使用任何其他东西。这是一个巨大的挑战project@reza-为避免混淆,删除了spring批次详细信息,因为其不符合您的要求。Spring批处理遵循jakarta ee批处理规范,重新发明完整的批处理能力对于处理庞大的容量和可维护性来说并不难
                -------------------UPDATE-----------------------