遇到一个有意思的业务。
有两个单列文件,一个500M一个700M,共1.2G,2E个数据,要将这两个单列文件中的数据提取出来去重。
最简单的思路,理论大小为1.2G的数据塞进Set里直接去重,发现程序跑着跑着就跑不动了,用jstat查看,发现原来没有赋予初始化参数,默认的初始化堆内存太小,导致程序跑不动。
于是在启动的时候加上了-Xms3000m -Xmx3000m
再次启动,用jstat观察发现老年代占用一直在上涨,一段时间之后老年代被占满,Full GC也GC不掉老年代的对象,于是程序再次卡住不动,检查程序没有内存泄露/死循环之后,分析,理论大小1.2G的数据,为何会在内存中占用超过3G的堆内存。
首先检查了Set的内部实现,JDK中Set的实现是用HashMap实现的,而HashMap底层则是两个数组,这里关注到了Map中数组的自动扩容算法:当不停的向Map中put数据的过程中,如果数据量超过了Map中设置的阀值threshold,那么Map就会自动扩容,将原来数组中的数据复制到一个2倍于原来容量的新数组中。
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int)(newCapacity * loadFactor);
}
这里可以清楚的看到,Map在移动数据的过程中,需要新建一个数组,而当newCapacity大到一定数量级的时候,就会占用非常多的内存。通过跟踪检查,发现3G内存在数组扩容到5000w大小的时候就抗不住了,于是单独做了一个实验,单独的构造一个5000w大小的数组,观察其内存占用情况,发现确实需要非常多的内存。此为原因之一。
然后,又观察到,虽然构建大数组,需要很多的内存空间,但是这部分空间并没有大到内存无法承受。跟踪检查到,老年代被占满的时候,构造的Set里容纳了2700w个对象,粗略的估算3G被2700w个对象所占据,每个对象大约需要100个字节的大小(由于无法精确的减除掉数组和其他因素占用的内存,所以实际值肯定比100字节要小),但是文件数据为16位的字符串,换句话说,每个16位的字符串对象,在内存里占据了大约100个字节的空间,这比文件编码后的字符大小要大很多。结论:转化为对象的时候,数据会膨胀,并且体积膨胀的大小比我们想象的要更大得多。
最后,丢到hive里轻轻松松解决了问题。
分享到:
相关推荐
JAVA内存溢出问题总结 JAVA 内存溢出问题是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用的内存大于虚拟机能提供的最大内存。内存溢出问题可以从容器和程序类两个方面进行排查,容器问题...
MAT会展示出所有对象的统计信息,包括对象数量、占用内存大小等,这对于找出消耗内存最多的对象非常有帮助。 其次,MAT的"Leak Suspects"报告是其特色之一。这个报告会自动分析heap dump,找出可能导致内存泄漏的...
JVM的内存占用不仅关乎程序的性能,还直接影响到系统的整体资源利用率。例如,过高的内存占用可能导致系统资源紧张,影响其他运行的应用程序。因此,了解和控制Java程序的内存使用是非常重要的。 在不同的操作系统...
- 示例:使用`WeakHashMap`来存储对象引用,以减少内存占用。 ```java Map, Value> map = new WeakHashMap(); ``` 3. **合理使用静态变量**:尽量减少静态变量的使用,特别是不要让静态变量引用可变对象。 4. *...
HeapAnalyzer是一款Java内存分析工具,由IBM开发,它可以帮助开发者检查和分析Java堆内存的状态,找出可能存在的内存泄漏或者过度占用内存的对象。通过分析heap dump文件,HeapAnalyzer可以展示对象的分布情况,识别...
与C/C++等需要手动管理内存的语言不同,Java虚拟机(JVM)自动处理对象的创建与销毁过程。当通过`new`或反射方法创建对象时,这些对象在堆(Heap)区域分配内存,而对象的生命周期管理完全交由JVM完成。 Java的垃圾...
内存泄露是常见的问题,当不再使用的对象仍然被引用,无法被垃圾收集器回收。此外,栈内存用于存储方法局部变量,随着方法的调用和返回自动管理。 四、基础Java学习 学习Java的基础涉及语法、控制结构、异常处理、...
js中终于有了自己的List,类似于java中的List对象,本文件是源码,亲测有如下方法:add()、has(key)、size()、values()、并集union(Set)、子集subset(Set)、差集difference(Set)、交集intersection(Set)、remove(key...
这种问题的原因为Java虚拟机创建的对象太多,在进行垃圾回收之间,虚拟机分配的到堆内存空间已经用满了,与Heap space有关。解决这类问题有两种思路: 1. 检查程序,看是否有死循环或不必要地重复创建大量对象。...
本文将详细介绍如何通过合理设置SGA(共享全局区)来有效降低Oracle 10g在Windows XP系统中的内存占用,并确保日常学习与工作的正常进行。 #### 一、Oracle内存结构简介 Oracle数据库的内存结构主要由SGA和PGA两...
本文旨在深入探讨Java中的内存泄露问题及其解决方案。 #### Java的内存管理:GARBAGE COLLECTION详解 垃圾收集器(GC)在Java中扮演着至关重要的角色,它负责自动回收不再使用的对象所占用的内存。在Java中,所有...
本主题将深入探讨如何在Java中使用可变长数组来模拟内存的申请与释放过程。 首先,我们来了解内存的基本概念。内存分为两种主要类型:栈内存和堆内存。栈内存主要存放基本类型的变量和对象的引用,它的生命周期与...
在C#编程中,了解如何获取系统和特定进程的CPU及内存占用率是十分重要的,尤其是在进行性能监控或资源管理的场景下。本篇将详细解释如何实现这一功能,并提供相应的代码示例。 首先,我们要关注的是操作系统级别的...
本文将深入探讨Java中的两种重要容器类——`List`和`Set`,并分析它们之间的区别以及各自的适用场景。 #### 二、Java容器类List详解 **1. List接口简介** - `List`接口是`Collection`接口的一个子接口,主要特点...
内存泄漏是指程序中已经无法访问的内存块,由于各种原因无法释放,导致内存占用持续增长。 通过深入理解Java的反射机制和内存管理,开发者能够更好地优化代码,避免内存泄漏,提高程序的可扩展性和性能。文档中的...
### Java内存监控工具Java VisualVM #### 一、概述 Java VisualVM是一款强大的Java应用程序性能分析和诊断工具,主要用于监控和分析Java应用的运行时行为,包括但不限于内存使用情况、线程状态、CPU使用率等关键...
以下将详细介绍Java中List、Set与Array之间的转换方法。 1. **List与Array的转换** - **Array转List**: 如果你有一个数组,可以使用`Arrays.asList()`方法将其转换为List。例如: ```java String[] array = {...
SQL Server 的内存占用是一个常见的问题,许多开发者和dba 都会遇到这种问题。解决这个问题的关键是理解 SQL Server 的内存占用结构和执行缓存的优化方法。在这篇文章中,我们将介绍 SQL Server 的内存占用结构,并...
比如在类Index中的getDictionary方法中,需要返回所有保存的Term,可以直接调用map结构的keySet方法返回一个Set对象,包含了所有的键,也即所有的Term,类似的还有由于实现了子类的compareTo以及equal方法,对于子类...
Java CopyUtil工具类,可以进行对象的深copy,比如:对象里面包含对象,对象里面包含Map,List,Set...等复杂类型的属性都可以copy,copy后的对象与原有对象没有联系,即改变原有对象内容,不会改变copy后的对象里面的...