JAVA GC

 

一、内存溢出类型
1、java.lang.OutOfMemoryError: PermGen space 

JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。


2、java.lang.OutOfMemoryError: Java 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值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。


垃圾回收GC的角色

JVM调用GC的频度还是很高的,主要两种情况下进行垃圾回收:

当应用程序线程空闲;另一个是java内存堆不足时,会不断调用GC,若连续回收都解决不了内存堆不足的问题时,就会报out of memory错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。

根据GC的机制,程序的运行会引起系统运行环境的变化,增加GC的触发机会。

为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和GC的开销。显示调用System.GC()只能建议JVM需要在内存中对垃圾对象进行回收,但不是必须马上回收,

一个是并不能解决内存资源耗空的局面,另外也会增加GC的消耗。

二、JVM内存区域组成
简单的说java中的堆和栈

java把内存分两种:一种是栈内存,另一种是堆内存

1。在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;

2。堆内存用来存放由new创建的对象和数组

在函数(代码块)中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的内存空间;在堆中分配的内存由java虚拟机的自动垃圾回收器来管理


堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢;

栈的优势是存取速度比堆要快,缺点是存在栈中的数据大小与生存期必须是确定的无灵活性。


java堆分为三个区:New、Old和Permanent

GC有两个线程:

新创建的对象被分配到New区,当该区被填满时会被GC辅助线程移到Old区,当Old区也填满了会触发GC主线程遍历堆内存里的所有对象。Old区的大小等于Xmx减去-Xmn


java栈存放

栈调整:参数有+UseDefaultStackSize -Xss256K,表示每个线程可申请256k的栈空间

每个线程都有他自己的Stack


三、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 ,大大降低了性能


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"



四、性能检查工具使用
定位内存泄漏:

JProfiler工具主要用于检查和跟踪系统(限于Java开发的)的性能。JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视JVM运行情况及其性能。

1. 应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位; 

2. 应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次; 

3. 应用服务器经常做Full GC(Garbage Collection),而且时间很长,大约需要30-40秒,应用服务器在做Full GC的时候是不响应客户的交易请求的,非常影响系统性能。 


因为开发环境和产品环境会有不同,导致该问题发生有时会在产品环境中发生,通常可以使用工具跟踪系统的内存使用情况,在有些个别情况下或许某个时刻确实是使用了大量内存导致out of memory,这时应继续跟踪看接下来是否会有下降,

如果一直居高不下这肯定就因为程序的原因导致内存泄漏。


五、不健壮代码的特征及解决办法
1、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。

对于仍然有指针指向的实例,jvm就不会回收该资源,因为垃圾回收会将值为null的对象作为垃圾,提高GC回收机制效率;

2、我们的程序里不可避免大量使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域;

String str = "aaa"; 

String str2 = "bbb"; 

String str3 = str + str2;//假如执行此次之后str ,str2以后再不被调用,那它就会被放在内存中等待Javagc去回收,程序内过多的出现这样的情况就会报上面的那个错误,建议在使用字符串时能使用StringBuffer就不要用String,这样可以省不少开销; 


3、尽量少用静态变量,因为静态变量是全局的,GC不会回收的;

4、避免集中创建对象尤其是大对象,JVM会突然需要大量内存,这时必然会触发GC优化系统内存环境;显示的声明数组空间,而且申请数量还极大。

这是一个案例想定供大家警戒

使用jspsmartUpload作文件上传,运行过程中经常出现java.outofMemoryError的错误,

检查之后发现问题:组件里的代码

m_totalBytes = m_request.getContentLength();

m_binArray = new byte[m_totalBytes];

问题原因是totalBytes这个变量得到的数极大,导致该数组分配了很多内存空间,而且该数组不能及时释放。解决办法只能换一种更合适的办法,至少是不会引发outofMemoryError的方式解决。参考:http://bbs.xml.org.cn/blog/more.asp?name=hongrui&id=3747


5、尽量运用对象池技术以提高系统性能;生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。

6、不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。可以适当的使用hashtable,vector 创建一组对象容器,然后从容器中去取那些对象,而不用每次new之后又丢弃

7、一般都是发生在开启大型文件或跟数据库一次拿了太多的数据,造成 Out Of Memory Error 的状况,这时就大概要计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。

 

原帖:http://tieba.baidu.com/f?kz=816812930

03-28
<think>好的,用户想了解Java的垃圾回收机制以及性能调优。我需要先整理一下已有的引用内容,然后根据这些信息构建一个清晰的回答结构。 首先,查看用户提供的引用内容。引用1提到了Full GC和Concurrent Garbage Collection,引用2介绍了G1 GC作为CMS的替代品,引用3和4是用户的学习经历和一些基础概念。我需要确保回答涵盖垃圾回收的基本原理、不同收集器的类型以及调优方法。 接下来,需要确定回答的结构。可能分为几个部分:垃圾回收的基本概念、常见的垃圾回收器(如Serial、Parallel、CMS、G1)、性能调优的方法,以及相关问题。这样用户能逐步理解。 然后,要注意用户提到的系统级指令,比如使用正确的中文回答,数学公式用$...$,独立公式用$$...$$。不过在这个问题中可能数学公式不多,但如果有涉及算法复杂度的地方需要正确应用,比如时间复杂度O(n)之类的。 还要生成相关问题,放在最后。问题需要与Java GC相关,可能涉及不同收集器的比较、调优参数、监控工具等。 需要确保引用的正确使用。比如在提到Full GC时引用[^1],G1 GC时引用[^2]。用户提供的引用3和4可能作为补充,但可能内容较为基础,可以适当引用。 可能遗漏的点是具体的调优参数示例,比如-Xmx、-XX:+UseG1GC等,这些需要包含在调优方法中。此外,监控工具如jstat、GC日志分析也是调优的重要部分,需要提到。 还要注意避免过于技术化的术语,保持解释清晰易懂,符合用户可能的中级水平。同时,确保每个部分的信息准确,比如G1 GC的特点,CMS的缺点等。 最后,检查是否符合格式要求:使用中文,引用标识自然添加,代码块(如果有的话)正确使用语法,分点回答结构清晰。生成的相关问题需要有意义,能够引导用户进一步学习。 总结,回答结构大致如下: 1. 垃圾回收机制概述 2. 主要垃圾回收器类型及特点(包括Serial、Parallel、CMS、G1) 3. 性能调优方法(参数调整、监控工具、避免Full GC等) 4. 相关问题列表 在写作过程中,确保每个部分的信息准确,正确引用提供的资料,并自然融入回答中。</think># Java垃圾回收机制与性能调优指南 ## 一、垃圾回收机制基础 Java垃圾回收(Garbage Collection, GC)通过自动内存管理实现对象生命周期控制。核心原理是识别不再被引用的对象并释放其内存空间。JVM内存区域划分包括: - 新生代(Young Generation):存放新创建对象,分为Eden区和两个Survivor区 - 老年代(Old Generation):长期存活对象存储区 - 元空间(Metaspace):类元数据存储区(替代永久代) 触发GC的条件包括内存分配失败或显式调用`System.gc()`[^4]。 ## 二、主流垃圾回收器对比 | 回收器类型 | 工作模式 | 适用场景 | 特点 | |-------------------|------------------|--------------------------|-------------------------------| | Serial GC | 单线程STW | 客户端应用 | 简单低延迟,吞吐量低 | | Parallel GC | 多线程STW | 吞吐量优先 | 默认回收器,高吞吐量 | | CMS GC | 并发标记清除 | 低延迟场景 | 减少停顿时间,内存碎片问题| | G1 GC | 分区并发回收 | 大内存低延迟 | 可预测停顿,吞吐量优化 | | ZGC/Shenandoah | 超低延迟 | 超大堆内存 | 亚毫秒级停顿 | *注:STW(Stop-The-World)指暂停所有应用线程* ## 三、性能调优方法 ### 3.1 参数调优 ```bash # 基础配置示例 -Xmx4g -Xms4g # 堆内存上下限 -XX:+UseG1GC # 启用G1收集器 -XX:MaxGCPauseMillis=200 # 目标最大停顿时间 -XX:ParallelGCThreads=4 # 并行线程数 ``` ### 3.2 监控工具 - `jstat -gcutil <pid>`:实时GC统计 - `jmap -histo:live <pid>`:堆内存直方图 - VisualVM/GCViewer:可视化分析GC日志 ### 3.3 优化策略 1. **避免Full GC**:通过`-XX:+DisableExplicitGC`禁止显式GC调用 2. **对象分配优化**: - 减少大对象直接进入老年代 - 使用对象池复用实例 3. **GC日志分析**: ```bash -XX:+PrintGCDetails -Xloggc:/path/to/gc.log ``` ### 3.4 G1调优专项 $$ \text{Region大小} = \min(\text{堆大小}/2048, 32\text{MB}) $$ 调整`-XX:G1HeapRegionSize`可优化内存利用率 ## 四、典型问题解决方案 **场景1:频繁Full GC** - 检查内存泄漏(MAT工具分析堆转储) - 增大老年代空间或调整晋升阈值 **场景2:长时间GC停顿** - 切换低延迟收集器(G1/ZGC) - 调整`-XX:InitiatingHeapOccupancyPercent`触发阈值 **场景3:Metaspace溢出** - 增加`-XX:MaxMetaspaceSize` - 检查类加载器泄漏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值