当前位置: 首页 > 知识库问答 >
问题:

java - 多线程并发查询百万数据的内存占用问题?

施招
2023-11-06

开启十个线程,每个线程都会去查询500W的数据。

  @Test    void testThread() throws InterruptedException {        int size = 10;        CountDownLatch countDownLatch = new CountDownLatch(size);        for (int i = 0; i < size; i++) {            CompletableFuture.runAsync(() -> {                testPage();                countDownLatch.countDown();            });        }        countDownLatch.await();    }@Test    void testPage(){        //查询出表中总记录数        Long total = orderMapper.selectCount(null);        //每次分页读取的结果数        int fetchSize = 100000;        // 分页优化参数,上次查询的最大ID        int lastMaxId = 0;        for (int i = 0; i < (total / fetchSize) + 1; i++) {            LambdaQueryWrapper<Order> orderLambdaQueryWrapper = new LambdaQueryWrapper<>();            orderLambdaQueryWrapper.gt(Order::getOrderId, lastMaxId);            List<Order> records = orderMapper.selectPage(new Page<>(1, fetchSize), orderLambdaQueryWrapper).getRecords();           records.stream().forEach(System.out::println);            //获取本次最大的Id            lastMaxId = records.get(records.size() - 1).getOrderId();        }    }

单独一个线程,堆内存占用500M。
image.png
十个线程,堆内存占用最高也不过1400MB,为什么会这样呢?这些内存占用居然不会叠加的吗?
image.png

共有1个答案

巢皓君
2023-11-06

这个问题涉及到Java内存管理和多线程的并发控制。

首先,Java的内存管理是分代的。堆内存是其中最大的一部分,它被所有的线程共享。当你创建一个线程时,它会有自己的栈,但堆内存是共享的。这意味着每个线程都会使用相同的堆内存,而不是每个线程都有自己的堆内存。

其次,关于你的测试结果,这可能是因为Java的垃圾回收(GC)机制。当一个线程结束时,它的内存会被回收,包括堆内存。这就是为什么你在十个线程运行时,堆内存使用并没有叠加。每次线程结束,它使用的内存都会被回收,然后再被其他线程使用。

此外,你的代码中使用了流操作(stream),流操作在处理完数据后会自动关闭,这可能也是内存得到释放的原因之一。

最后,你可能在程序运行时启用了某些Java虚拟机(JVM)参数或垃圾收集器,这可能会影响内存使用情况。例如,你可能启用了并行垃圾收集器(Parallel GC),它通常能提供更好的吞吐量,但可能会导致更多的内存占用。

总的来说,你的代码和程序运行情况共同决定了你的内存使用情况。你的程序可能并没有产生大量的内存溢出,因为你的代码合理地管理了内存,并且垃圾回收器也有效地回收了不再使用的内存。

 类似资料:
  • 我在表里添加了500W的测试数据,表中数据如下 一次性读取 500w 数据到 JVM 内存中 必然会造成OOM现象,所以我分别试验了2个读取百万数据的方式,并用Junit分析内存占用 分页多次查询,并进行深度分页优化 Mybatis的流式查询 我从网上看了许多博客,说流式查询可以很好避免OOM问题。 但是为什么在分析堆内存占用中,反而是 多次分页查询的内存占用更小,平均只有400MB 而流式查询却

  • 问题内容: 有没有办法找出我的Java线程在虚拟机中占用多少内存? 例如,使用堆栈跟踪转储或其他某种方式。 问题答案: Java线程将堆用作共享内存。各个线程都有其堆栈(您可以通过-Xss命令行选项设置其大小,默认为512KB),但是所有其他内存(堆)都不属于特定线程,并询问一个特定线程仅使用了多少内存没有道理。

  • 当我研究线程及其占用的内存(线程堆栈)时,我决定做一个简单的负载测试,看看线程的数量如何影响我的计算机上的RAM。 所以,在测试中,我使用了Tomcat,在设置中。xml将最小和最大web容器线程池设置为200。在那之后,我在将pool设置为2000时也做了同样的操作。我很震惊,因为内存占用没有差异(通过Windows任务管理器进行检查),而且几乎是一样的。所以我认为这些线程可能必须处于运行状态,

  • 嗨,我对java编程还比较陌生。我编写的下面的程序似乎占用了很多内存(大约240 MB,正常吗?-我不这么认为!)请建议一些方法来优化这个程序,以便减少内存存储。 程序-- 代码-

  • 为什么我的java PID占用更多内存。目前我有24GB ram和max-xmx=15G。所以java PID的解决方案是占用更少的内存。 23794 root 0 22.2g 16.5g 13416 s 100.070.42980:54上面的java是我的最高命令结果。任何人都知道如何重新关注这个问题。

  • 共享内存 在消息传递之外,还存在一种广为人知的并发模型,那就是共享内存。其实如果不能共享内存,消息传递也是不能在不同的线程间传递消息,也谈不上在不同的线程间等待和通知了。共享内存是这一切得以发生的基础。如果查看源码,你会发现消息传递的内部实现就是借用了共享内存机制。相对于消息传递而言,共享内存会有更多的竞争,但是不用进行多次拷贝,在某些情况下,也需要考虑使用这种方式来处理。在Rust中,能共享内存