当前位置:首页 > 数码 > 技术-内存再也不会溢出的-Java-一次性处理百万数据 (内存技术设备是什么)

技术-内存再也不会溢出的-Java-一次性处理百万数据 (内存技术设备是什么)

admin7个月前 (04-19)数码22
背景 最近在使用同事编写的后台管理系统导出数据进行数据分析,但前端一直出现卡顿。经查询服务器日志后发现内存溢出。分析原因是由于表数据量过大(超过百万),查询出的数据直接占满内存。 解决思路 1. 传统思路:分页查询 分页查询将大数据集分成小数据集分别查询,但当数据量较大时,分页查询的效率会很低。 分页查询关键代码: java public Page findUsers(int page, int size) { return userRepository.findAll(PageRequest.of(page - 1, size)); } 分页查询还可以使用线程池进行优化,但需要注意线程安全。 2. 流式查询 流式查询可以一边从数据库读取数据,一边进行处理,提高数据处理效率。由于流式查询逐行读取数据,查询速度可能受到影响。为了提高性能,可以适当调整 fetchsize。 注解写法: java @Query("select from user") List findUsers(@Param("limit") int limit, ResultHandler resultHandler); 请注意方法中增加了 ResultHandler(回调处理),这是与传统查询的区别。 流式查询对比结果 分页查询耗时300多秒,而流式查询仅需5秒左右,效率大大优于分页查询。 总结 流式查询是一种非常好的技术,但也有其限制条件。在使用之前,请确保你的数据库支持流式查询。

如何防止java中的内存泄漏

技术

尽管java虚拟机和废品回收机制治理着大部分的内存事务,但是在java软件中还是可能存在内存泄漏的情况。 的确,在大型工程中,内存泄漏是一个普遍问题。 避免内存泄漏的第一步,就是要了解他们发生的原因。 这篇文章就是要介绍一些常见的缺陷,然后提供一些非常好的实践例子来指导你写出没有内存泄漏的代码。 一旦你的程序存在内存泄漏,要查明代码中引起泄漏的原因是很困难的。 同时这篇文章也要介绍一个新的工具来查找内存泄漏,然后指明发生的根本原因。 这个工具轻易上手,可以让你找到产品级系统中的内存泄漏。 废品回收(GC)的角色虽然废品回收关心着大部分的问题,包括内存治理,使得程序员的任务显得更加轻松,但是程序员还是可能犯些错误导致内存泄漏问题。 GC(废品回收)通过递归对所有从“根”对象(堆栈中的对象,静态数据成员,JNI句柄等等)继续下来的引用进行工作,然后标记所有可以访问的活动着的对象。 而这些对象变成了程序唯一能够操纵的对象,其他的对象都被释放了。 因为GC使得程序不能够访问那些被释放的对象,所以这样做是安全的。 内存治理可以说是自动的,但是这并没有让程序员脱离内存治理问题。 比方说,对于内存的分配(还有释放)总是存在一定的开销,尽管这些开销对程序员来说是隐含的。 一个程序假如创建了很多对象,那么它就要比完成相同任务而创建了较少对象的程序执行的速度慢(假如其他的条件都相同)。 文章更多想说的,导致内存泄漏主要的原因是,先前申请了内存空间而忘记了释放。 假如程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让废品回收器验证这些对象是否不再需要。 正如我们前面看到的,假如存在对象的引用,这个对象就被定义为“活动的”,同时不会被释放。 要确定对象所占内存将被回收,程序员就要务必确认该对象不再会被使用。 典型的做法就是把对象数据成员设为null或者从集合中移除该对象。 注重,当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理。 从更高一个层次看,这就是所有存在内存管的语言对内存泄漏所考虑的事情,剩余的对象引用将不再会被使用。 典型的泄漏既然我们知道了在java中确实会存在内存泄漏,那么就让我们看一些典型的泄漏,并找出他们发生的原因。 全局集合在大型应用程序中存在各种各样的全局数据仓库是很普遍的,比如一个JNDI-tree或者一个session table。 在这些情况下,注重力就被放在了治理数据仓库的大小上。 当然是有一些适当的机制可以将仓库中的无用数据移除。 可以有很多不同的解决形式,其中最常用的是一种周期运行的清除作业。 这个作业会验证仓库中的数据然后清除一切不需要的数据。 另一个办法是计算引用的数量。 集合负责跟踪集合中每个元素的引用者数量。 这要求引用者通知集合什么时候已经对元素处理完毕。 当引用者的数目为零时,就可以移除集合中的相关元素。 高速缓存高速缓存是一种用来快速查找已经执行过的操作结果的数据结构。 因此,假如一个操作执行很慢的话,你可以先把普通输入的数据放入高速缓存,然后过些时间再调用高速缓存中的数据。 高速缓存多少还有一点动态实现的意思,当数据操作完毕,又被送入高速缓存。 一个典型的算法如下所示:1. 检查结果是否在高速缓存中,存在则返回结果;2. 假如结果不在,那么计算结果;3. 将结果放入高速缓存,以备将来的操作调用。 这个算法的问题(或者说潜在的内存泄漏)在最后一步。 假如操作是分别多次输入,那么存入高速缓存的内容将会非常大。 很明显这个方法不可取。 为了避免这种潜在的致命错误设计,程序就必须确定高速缓存在他所使用的内存中有一个上界。 因此,更好的算法是:1. 检查结果是否在高速缓存中,存在则返回结果;2. 假如结果不在,那么计算结果;3. 假如高速缓存所占空间过大,移除缓存中旧的结果;4. 将结果放入高速缓存,以备将来的操作调用。 通过不断的从缓存中移除旧的结果,我们可以假设,将来,最新输入的数据可能被重用的几率要远远大于旧的结果。 这通常是一个不错的设想。 这个新的算法会确保高速缓存的容量在预先确定的范围内。 精确的范围是很难计算的,因为缓存中的对象存在引用时将继续有效。 正确的划分高速缓存的大小是一个复杂的任务,你必须权衡可使用内存大小和数据快速存取之间的矛盾。 另一个解决这个问题的途径是使用类来将对象放入高速缓存。 这个方法可以保证当虚拟机用完内存或者需要更多堆的时候,可以释放这些对象的引用。 类装载器  Java类装载器创建就存在很多导致内存泄漏的漏洞。 由于类装载器的复杂结构,使得很难得到内存泄漏的透视图。 这些困难不仅仅是由于类装载器只与“普通的”对象引用有关,同时也和对象内部的引用有关,比如数据变量,方法和各种类。 这意味着只要存在对数据变量,方法,各种类和对象的类装载器,那么类装载器将驻留在JVM中。 既然类装载器可以同很多的类关联,同时也可以和静态数据变量关联,那么相当多的内存就可能发生泄漏。 定位内存泄漏  经常地,程序内存泄漏的最初迹象发生在出错之后,在你的程序中得到一个OutOfMemoryError。 这种典型的情况发生在产品环境中,而在那里,你希望内存泄漏尽可能的少,调试的可能性也达到最小。 也许你的测试环境和产品的系统环境不尽相同,导致泄露的只会在产品中暴露。 这种情况下,你需要一个低负荷的工具来监听和寻找内存泄漏。 同时,你还需要把这个工具同你的系统联系起来,而不需要重新启动他或者机械化你的代码。 也许更重要的是,当你做分析的时候,你需要能够同工具分离而使得系统不会受到干扰。 一个OutOfMemoryError经常是内存泄漏的一个标志,有可能应用程序的确用了太多的内存;这个时候,你既不能增加JVM的堆的数量,也不能改变你的程序而使得他减少内存使用。 但是,在大多数情况下,一个OutOfMemoryError是内存泄漏的标志。 一个解决办法就是继续监听GC的活动,看看随时间的流逝,内存使用量是否会增加,假如有,程序中一定存在内存泄漏。 具体输出有很多办法来监听废品回收器的活动。 也许运用最广泛的就是以:-Xverbose:gc选项运行JVM,然后观察输出结果一段时间。 [memory] 10.109-10.235: GC K->K (K), 126.000 ms箭头后的值(在这个例子中 K)是废品回收后堆的使用量。 控制台观察这些无尽的GC具体统计输出是一件非常单调乏味的事情。 好在有一些工具来代替我们做这些事情。 The JRockit Management Console可以用图形的方式输出堆的使用量。 通过观察图像,我们可以很方便的观察堆的使用量是否伴随时间增长。 Figure 1. The JRockit Management Console治理控制台甚至可以配置成在堆使用量出现问题(或者其他的事件发生)时向你发送邮件。 这个显然使得监控内存泄漏更加轻易。 内存泄漏探测工具  有很多专门的内存泄漏探测工具。 其中The JRockit Memory Leak Detector可以供来观察内存泄漏也可以针对性地找到泄漏的原因。 这个强大的工具被紧密地集成在JRockit JVM中,可以提供最低可能的内存事务也可以轻松的访问虚拟机的堆。 专门工具的优势一旦你知道程序中存在内存泄漏,你需要更专业的工具来查明为什么这里会有泄漏。 而JVM是不可能告诉你的。 现在有很多工具可以利用了。 这些工具本质上主要通过两种方法来得到JVM的存储系统信息的:JVMTI和字节码仪器。 Java虚拟机工具接口(JVMTI)和他的原有形式JVMPI(压型接口,PRofiling Interface)都是标准接口,作为外部工具同JVM进行通信,搜集JVM的信息。 字节码仪器则是引用通过探针获得工具所需的字节信息的预处理技术。 通过这些技术来侦测内存泄漏存在两个缺点,而这使得他们在产品级环境中的运用不够理想。 首先,根据两者对内存的使用量和内存事务性能的降级是不可以忽略的。 从JVM获得的堆的使用量信息需要在工具中导出,收集和处理。 这意味着要分配内存。 按照JVM的性能导出信息是需要开销的,废品回收器在搜集信息的时候是运行的非常缓慢的。 另一个缺点就是,这些工具所需要的信息是关系到JVM的。 让工具在JVM开始运行的时候和它关联,而在分析的时候,分离工具而保持JVM运行,这显然是不可能的。 既然JRockit Memory Leak Detector是被集成到JVM中的,那么以上两种缺点就不再存在。 首先,大部分的处理和分析都是在JVM中完成的,所以就不再需要传送或重建任何数据。 处理也可以建立在废品回收器的基础上,即提高速度。 再有,内存泄漏侦测器可以同一个运行的JVM关联和分离,只要JVM在开始的时候伴随着 –Xmanagement选项(通过远程JMX接口答应监听和治理JVM)。 当工具分离以后,工具不会遗留任何东西在JVM中;JVM就可以全速运行代码就似乎工具关联之前一样。

现在有百万条数据通过java程序读到txt文件里并打包,报内存溢出生成javac

一、设置JVM内存设置

1.设置JVM内存的参数有四个:

-XmxJavaHeap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定;

-XmsJavaHeap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值;

-XmnJavaHeapYoung区大小,不熟悉最好保留默认值;

-Xss每个线程的Stack大小,不熟悉最好保留默认值;

2.如何设置JVM内存分配:

(1)当在命令提示符下启动并使用JVM时(只对当前运行的类Test生效):

java-Xmx128m-Xms64m-Xmn32m-Xss16mTest

(2)当在集成开发环境下(如eclipse)启动并使用JVM时:

a.在eclipse根目录下打开,默认内容为(这里设置的是运行当前开发工具的JVM内存分配):

-vmargs表示以下为虚拟机设置参数,可修改其中的参数值,也可添加-Xmn,-Xss,另外,内还可以设置非堆内存,如:-XX:PermSize=56m,-XX:MaxPermSize=128m。

免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。

标签: java