一、JVM内存区域组成
java 把内存分四种
1、栈区(stack segment)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等,具体方法执行结束之后,系统自动释放内存资源
2、堆区(heap segment) — 一般由程序员分配释放,存放由new创建的对象和数组,jvm不定时查看这个对象,如果没有引用指向这个对象就回收
3、静态区(data segment)— 存放全局变量,静态变量 和字符串常量,不释放
4、代码区(code segment)— 存放程序中方法的二进制代码,而且是多个对象 共享一个代码空间区域
在方法(代码块)中定义一个变量时,java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,java 会自动释放掉为该变量所分配的内存空间;
在堆中分配的内存由java 虚拟机的自动垃圾回收器来管理,堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢;栈的优势是存取速度比堆要快,缺点是存在栈中的数据大小与生存期必须是确定的无灵活性.
java 堆由Perm区和Heap区组成,Heap区则由Old区 和New区组成,而New区又分为Eden区, From区, To区,Heap = {Old + NEW = { Eden, From, To } },见图1所示。
Heap区分两大块,一块是 NEW Generation, 另一块是Old Generation. 在New Generation中,有一个叫Eden的空间,主要是用来存放新生的对象,还有两个Survivor Spaces(from,to), 它们用来存放每次垃圾回收后存活下来的对象。在Old Generation中,主要存放应用程序中生命周期长的内存对象,还有个Permanent Generation,主要用来放JVM自己的反射对象,比如类对象和方法对象等。
在New Generation块中,垃圾回收一般用Copying的算法,速度快。每次GC的时候,存活下来的对象首先由Eden拷贝到某个Survivor Space, 当Survivor Space空间满了后, 剩下的live对象就被直接拷贝到Old Generation中去。因此,每次GC后,Eden内存块会被清空。在Old Generation块中,垃圾回收一般用mark-compact的算法,速度慢些,但减少内存要求.
垃圾回收分多级,0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾;1级或以上为部分垃圾回收,只会回收NEW中的垃圾,内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java 对象的情况。
JVM调用GC的频度还是很高的,主要两种情况下进行垃圾回收:当应用程序线程空闲;另一个是java 内存堆不足时,会不断调用GC,若连续回收都解决不了内存堆不足的问题时,就会报out of memory错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。
根 据GC的机制,程序的运行会引起系统运行环境的变化,增加GC的触发机会。为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和GC的开销。 显示调用System.GC()只能建议JVM需要在内存中对垃圾对象进行回收,但不是必须马上回收,一个是并不能解决内存资源耗空的局面,另外也会增加 GC的消耗。
当一个URL被访问时,内存申请过程如下:
A. JVM会试图为相关Java 对象在Eden中初始化一块内存区域
B. 当Eden空间足够时,内存申请结束。否则到下一步
C. JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收), 释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区
D. Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区 空间足够时,Survivor区的对象会被移到Old区 ,否则会被保留在Survivor区
E. 当OLD区 空间不够时,JVM会在OLD区 进行完全的垃圾收集(0级)
F. 完全垃圾收集后,若Survivor及OLD区 仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现"out of memory错误"
二、内存溢出类型
1、java .lang.OutOfMemoryError: PermGen space
JVM 管理两种类型的内存,堆和非堆。堆是给开发人员用的,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不 会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者 tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。
2、java .lang.OutOfMemoryError:
2Javaheap space
这种内存溢出是最常见的情况之一,主要体现在Old区 的 溢出,产生的原因可能是:1) 设置的内存参数过小(ms/mx, NewSize/MaxNewSize);2) 程序问题。Heap space其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。如果内存剩余不到40%,JVM就会增大堆到Xmx 设置的值,内存剩余超过70%,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大 小。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了.
注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来.
3、java .lang.OutOfMemoryError: c heap space
系统对C Heap没有限制,故C Heap发生问题时,Java 进程所占内存会持续增长,直到占用所有可用系统内存
4、其他
JVM 有2个GC线程。第一个线程负责回收Heap的Young区。第二个线程在Heap不足时,遍历Heap,将Young 区升级为Older区。Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM的性能。
为什么一些程序频繁发生GC?有如下原因:
a、程序内调用了System.gc()或Runtime.gc()。
b、一些中间件软件调用自己的GC方法,此时需要设置参数禁止这些GC。
c、Java 的Heap太小,一般默认的Heap值都很小。
d、频繁实例化对象,Release对
象。此时尽量保存并重用对象,例如使用StringBuffer()和String()。
如果你发现每次GC后,Heap的剩余空间会是总空间的50%,这表示你的Heap处于健康状态。许多Server端的Java 程序每次GC后最好能有65%的剩余空间。
三、JVM如何设置虚拟内存
提示:在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。
提示:Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。
提 示:JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于 40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、 -Xmx相等以避免在每次GC 后调整堆的大小。
提示:假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位 处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G- 2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了
提示:注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。
提示:设置NewSize、MaxNewSize相等,"new"的大小最好不要大于"old"的一半,原因是old区 如果不够大会频繁的触发"主" GC ,大大降低了性能
提示:增加Heap Size 虽然会降低GC的频率,但也增加了每次GC的时间。并且GC运行时,所有的用户线程将暂停,也就是GC期间,Java 应用程序不做任何工作。
提示:Heap Size 并不决定进程的内存使用量。进程的内存使用量要大于-Xmx定义的值,因为Java 为其他任务分配内存,例如每个线程的Stack等。
提示:每个线程都有他自己的Stack,Stack Size 限制着线程的数量。如果Stack过大就好导致内存溢漏。-Xss参数决定Stack大小,例如-Xss1024K。如果Stack太小,也会导致Stack溢漏。
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
解决方法:手动设置Heap size
修改TOMCAT_HOME/bin/catalina.bat
在"echo "Using CATALINA_BASE: $CATALINA_BASE""上面加入以下行:
JAVA _OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"
四、不健壮代码的特征及解决办法
1、 尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄 露。对于仍然有指针指向的实例,jvm就不会回收该资源,因为垃圾回收会将值为null的对象作为垃圾,提高GC回收机制效率;
2、我们的程序里不可避免大量使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域;例如
3、尽量少用静态变量 ,因为静态变量 是全局的,GC不会回收的;
4、避免集中创建对象尤其是大对象,JVM会突然需要大量内存,这时必然会触发GC优化系统内存环境;显示的声明数组空间,而且申请数量还极大。
5、尽量运用对象池技术以提高系统性能;生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。
6、不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。可以适当的使用hashtable,vector 创建一组对象容器,然后从容器中去取那些对象,而不用每次new之后又丢弃
7、一般都是发生在开启大型文件或跟数据库一次拿了太多的数据,造成 Out Of Memory Error 的状况,这时就大概要计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。[/size]
分享到:
相关推荐
- **内存分块**:JVM内存分为线程栈区和堆区。 - **线程栈**:每个线程拥有自己的线程栈,存储了方法调用信息。所有原始类型的局部变量保存在线程栈中,且线程之间是独立的。 ### 垃圾回收机制与双亲委派机制 ####...
《JVM性能调优-JVM内存整理及GC回收》是一份深入探讨Java虚拟机(JVM)优化的重要学习资料,特别适合对JAVA编程有经验的开发者。这份文档详细阐述了JVM性能调优的关键概念,包括JVM内存模型、垃圾回收(Garbage ...
在详细介绍Java 8内存模型之前,需要了解的是,JVM(Java虚拟机)在启动时,操作系统会为JVM进程分配一系列内存区域,这些内存区域包括堆(Heap)、元空间(MetaSpace)、线程堆栈(Thread Stack)、共享库(Shared ...
3. **JVM内存设置不当**:默认的JVM内存设置可能不足以应对大规模索引任务,例如堆内存大小(-Xms, -Xmx)设置过小。 4. **内存泄漏**:程序中的某些对象未被正确释放,导致内存持续占用。 为了解决JVM运行时内存...
3. **设置合适的内存参数**:在JVM启动时,可以增加堆内存大小,例如使用`-Xms`和`-Xmx`选项。然而,这并不是长久之计,因为增加内存可能会导致其他问题,如垃圾收集性能下降。 4. **减少对象创建**:在处理Excel...
2. **设置内存大小**:在使用POI时,可以调整Java虚拟机(JVM)的堆内存大小,例如通过增加`-Xmx`参数。但这种方法并不能根本解决问题,因为内存限制仍然存在,尤其是在处理大量数据时。 3. **迭代读取行**:使用...
3. 避免长时间持有大对象或大量对象:对大对象,尽量使用流式处理或分块处理,减少内存压力。避免一次性加载大量数据,而是采用分页或者按需加载的方式。 4. 及时释放资源:在不再使用对象时,确保取消对其的引用,...
3. 调整JVM内存设置:增加JVM的堆内存大小(通过-Xms和-Xmx参数),但这只是临时解决方案,并不能从根本上解决问题,因为增加内存可能导致其他性能问题。 4. 使用内存映射文件(Memory-Mapped Files):虽然JXL不...
3. **内存管理**:分析JVM内存模型,包括堆、栈、方法区、元空间等区域,重点讨论垃圾收集机制,如分代收集、标记-清除、复制、标记-整理和分块算法等。 4. **JVM性能调优**:介绍如何通过调整JVM参数来优化应用...
2. **分块处理**:在程序中,每次只加载一个或几个小XML文件到内存,处理完后再释放内存,确保内存始终在可控范围内。 3. **文件拼装**:当需要完整的XML数据时,程序可以通过按顺序读取并合并这些小文件来重建原始...
2. 性能优化:对于大文件,分块读取可以减少内存压力并提高性能。 3. 错误处理:处理内存映射文件时,必须考虑可能出现的错误,如文件不存在、内存不足等。 4. 并发访问:在多线程环境中,需要确保对内存映射文件的...
综上所述,解决 POI 读取 Excel 文件时的内存溢出问题,主要通过切换到事件模型、分块读取、压缩工作簿以及合理配置 JVM 参数等方式。这些策略能够显著降低内存占用,提高程序的稳定性和可扩展性。
此外,还可以考虑使用Java的内存映射文件(Memory-Mapped File)技术,将文件映射到操作系统的虚拟内存空间,从而减轻对JVM堆内存的压力。 本资源提供的"junrar的bug解决"文件包含了修复此问题的源码修改。修改主要...
1. **内存管理**:JVM内存模型中,堆和栈的分配策略对性能有很大影响。垃圾收集机制是自动内存管理的关键,包括分代收集、标记-清除、复制、标记-整理和分块收集等算法。理解如何优化对象创建、生存周期和内存分配能...
在处理大型或复杂PDF文档时,可能会遇到JVM内存不足的问题。这是因为PDF解析和操作通常需要消耗大量内存资源。为避免`OutOfMemoryError`,开发者需要确保JVM有足够的堆内存分配。这可以通过调整Java虚拟机的启动参数...
3. **内存管理**:JVM有自己的一套内存模型,包括堆内存(Heap)、方法区(Method Area)、栈内存(Stack)、本地方法栈(Native Method Stack)和程序计数器(PC Register)。堆内存主要存储对象实例,方法区存储类...
- 深入学习:理解JVM内存模型和垃圾回收机制,有助于更好地使用MAT。 6. **学习资源**: - 官方文档:Eclipse官方提供了详细的MAT用户手册和教程,是学习和使用MAT的重要参考。 - 社区讨论:Eclipse社区和Stack ...
内存消耗是性能优化的关键因素,因为过高的内存占用可能导致JVM进程崩溃或者系统响应速度减慢。 2. **分块读写**:为减轻内存压力,可以采用分块读取和写入的方式,即每次只处理一部分数据,而不是一次性加载整个...
11. **大文件合并**:面对内存限制,可以采用分块读取、合并再写入的策略,例如将文件分成多个小块读入内存,逐块处理并写入目标文件。 12. **快速查询统计**:在大量用户记录中查找看了5个电影以上的用户,可以...
1. **模块化结构**:Nginx支持各种模块,如过滤器模块,用于处理GZIP压缩、字节范围、分块响应和SSI。 2. **高性能**:采用内核Poll模型,能够处理大量并发连接,官方声称可以支持50,000个并发连接。 3. **高稳定性*...