JVM调优-解决native heap持续增长

本文针对JNI环境下出现的Java进程内存占用异常问题进行深入探讨。通过调整JVM参数,特别是增大GC频率,有效解决了NativeHeap内存占用过高的难题。具体包括控制heap大小、优化NewRatio参数及尝试MaxGCPauseMillis参数。

问题的提出,分析,请参考JNI——小心,内存怪兽出没

(简单的说起来,就是java进程占用了4G内存,但是折腾来折腾去,整个JVM的堆才100M上下,其余的内存凭空消失?刨根问底之后,原来是native heap占用了内存)

看完上面的问题,再来看解决方案:

 

 

 

目前看来,通过调整 JVM 参数来加大 GC 触发的频率是比较现实的一种方式。下面是一些分析过程:

 

一.       判断 Memonry 内存所属的区


通过 jconsole 可以看到 gc 信息,其中新生代的 scavenge 回收比较频繁,如果 Memonry 在这个区应该不存在长期得不到 gc 的情况

由此推测 Memory 应该是在 Tenured/old ,而这个区的内存回收次数恰好非常少。 当然参数优化的目标,就是加大 old 区的 gc 频率。

 

二.       观察 JVM 的堆参数配置

1. 默认配置下,堆的分配起始值为 126M ,最大 1.8G  


 

2. 观察 gc 前后 java 整个堆 的使用情况, gc 前大概占 130M, 远未达到默认设置下的内存容量


 

3. 进一步查看 old 区的内存 ,发现在 gc 前稳定在 90M

而默认参数初始分配 85M ,最大 1.3G ,显然很难触发到 GC


 

三.       解决问题

1. 首要的问题就是控制 JVM 对整个 heap 的大小分配:

 -Xmx300M    指定 jvm 的最大 heap 大小 ,

          -Xms40M   指定 jvm 的最小 heap 大小 ,

 

2. 在减小了整个堆的前提下,优化 NewRatio 这个参数 ( 指定 jvmOld Generation heap sizeNew Generation 的比例 )

            将默认的 NewRatio=2 更改为更符合业务实际内存使用比例的  -XX:NewRatio=1 

           减小了 old 区的比例,更容易触发 gc

 

         3. 另外一个猜测的可行方案:(有待验证)

启用 jvm 中的 gc 参数 -XX:MaxGCPauseMillis=<nnn>

这个参数的大概含义就是,让每次 gc 的时间不超过参数 nnn 。那么 nn 减少的时候,必然会增加到 gc 的次数,来换取每次 gc 的速度。

通过下图的数据可以求出,每次 old 区的 gc 平均耗时 34.7ms 那么可以   -XX:MaxGCPauseMillis=28 ,也许会增加到 gc 频率。


 

 

上述 4 个标红参数已经添加 ,观察几天得到的结论是,比较好的解决了这个问题。

====================================================================

分割线:下面是调优后的观察:

 

可以看到整个内存呈波动结构,Java的堆从20M--》60M就触发一次old区的gc。

下面看看GC的情况: MarkSweep是old区的gc策略,大概2个小时会触发一次,每次耗时

3194/112=28.5178ms,不会对应用产生明显的停摆,并且也验证了MaxGCPauseMillis参数的作用


 

 

<think>嗯,用户问的是JVM面试回答,得好好整理一下。首先,得确定用户可能是在准备面试,需要系统性的知识点和结构清晰的回答。要覆盖常见问题,同时结合实际场景,给出具体步骤和工具。 先想JVM的基础,肯定是内存结构,堆、方法区、栈这些。然后垃圾回收算法,比如标记清除、复制、标记整理,还有不同收集器像Serial、Parallel、CMS、G1、ZGC这些的区别和应用场景。这部分得简明扼要,但重点突出。 接下来,的步骤。可能用户需要知道如何诊断问题,比如OOM怎么排查,用什么工具,比如jstat、jmap、VisualVM这些。要提到分析内存泄漏,检查GC日志,整参数如堆大小、新生代老年代比例,选择合适的收集器。 然后,常见的参数,比如-Xms、-Xmx、-XX:NewRatio这些,还有CMS和G1相关的参数。这部分需要具体例子,比如如何设置堆大小,整GC线程数。 实战案例很重要,面试官喜欢听实际例子。比如高并发下的Full GC频繁,可能因为对象过早进入老年代,解决办法是整Survivor区大小或者年龄阈值。或者内存泄漏,用工具找出泄漏对象,修复代码。 注意事项方面,强避免过度,基准测试,分步骤整。可能用户会忽略监控和日志分析,这部分需要提醒。 最后,常见面试题,比如内存结构、垃圾回收算法、步骤、工具使用、参数例子。要总结回答的结构,让用户能按点陈述。 需要检查是否符合之前的系统指令,数学公式用不用?这里可能不太涉及,但如果有提到性能指标或公式,可能需要用LaTeX。不过JVM通常不涉及数学表达式,所以可能不需要。但用户给的例子里有变量用$...$,如果有变量的话,比如参数名,可能需要用,比如-XX:NewRatio=2中的2可能需要用$包裹?不过可能不需要,因为参数名本身不含数学符号。可能这里可以忽略,但得注意用户的要求。 回答结构要分点,每个部分用标题,比如内存结构、步骤、参数、案例、注意事项、常见问题。这样清晰易懂,符合用户的结构要求。语言用中文,避免术语错误,比如垃圾回收和垃圾收集可能混用,但统一用垃圾回收可能更好。 总结一下,回答应该覆盖基础概念、步骤、工具使用、参数示例、实际案例和注意事项,最后总结常见面试题,帮助用户系统化准备。需要确保信息准确,比如G1和ZGC的区别,CMS的缺点,避免过时信息,比如CMS在JDK9之后被废弃,可能建议使用G1或ZGC。</think>### JVM面试回答指南(结构化整理) --- #### **1. 基础概念** **1.1 JVM内存模型** - **堆(Heap)**:存放对象实例,分为`新生代`(Eden、Survivor区)和`老年代`。 - **方法区(Metaspace)**:存放类元数据(JDK8后替代永久代)。 - **虚拟机栈**:存储方法用栈帧(局部变量、操作数栈等)。 - **本地方法栈**:Native方法用。 - **程序计数器**:记录当前线程执行位置。 **1.2 垃圾回收(GC)算法** - **标记-清除**:简单但产生内存碎片。 - **复制算法**:适合新生代(Survivor区复制)。 - **标记-整理**:适合老年代(减少碎片)。 - **分代收集**:新生代用复制算法,老年代用标记-清除/整理。 **1.3 常见垃圾收集器** - **Serial/Serial Old**:单线程,适合客户端应用。 - **ParNew/Parallel Scavenge**:多线程新生代收集器。 - **CMS**:低停顿,但内存碎片和并发失败风险。 - **G1**:分Region、可预测停顿,适合大堆。 - **ZGC/Shenandoah**:超低停顿(JDK11+)。 --- #### **2. 核心步骤** **2.1 诊断问题** - **现象**:频繁Full GC、OOM、高GC停顿。 - **工具**: - `jstat -gcutil`:实时监控GC状态。 - `jmap -heap`:堆内存快照。 - `jstack`:线程堆栈分析。 - **VisualVM/Arthas**:图形化分析工具。 **2.2 分析GC日志** - 开启GC日志参数: ```bash -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log ``` - 关注指标: - Young GC/Full GC频率、耗时。 - 内存回收效率(如老年代增长速率)。 **2.3 整参数** - **堆大小**: - `-Xms`(初始堆)、`-Xmx`(最大堆),通常设为相等避免动态整。 - **新生代比例**: - `-XX:NewRatio=2`(老年代:新生代=2:1)。 - **Survivor区化**: - `-XX:SurvivorRatio=8`(Eden:Survivor=8:1:1)。 - **GC选择**: - 吞吐量先:`Parallel Scavenge + Parallel Old`。 - 低延迟:`G1`或`ZGC`。 --- #### **3. 高频参数示例** ```bash # 堆内存 -Xms4g -Xmx4g # 新生代比例 -XX:NewRatio=2 # G1参数 -XX:+UseG1GC -XX:MaxGCPauseMillis=200 # CMS参数 -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 # 内存溢出时Dump文件 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/dump.hprof ``` --- #### **4. 实战案例** **案例1:频繁Full GC** - **现象**:老年代快速填满,频繁Full GC。 - **分析**:对象过早晋升(Survivor区过小或年龄阈值低)。 - **解决**: - 增大Survivor区(`-XX:SurvivorRatio=4`)。 - 整晋升阈值(`-XX:MaxTenuringThreshold=15`)。 **案例2:内存泄漏** - **现象**:堆内存持续增长,OOM。 - **分析**:用`jmap -histo`查找大对象,`MAT`分析引用链。 - **解决**:修复代码中未释放的资源(如未关闭连接)。 --- #### **5. 注意事项** - **避免过度**:化代码(如减少大对象、缓存复用)。 - **基准测试**:后需压测验证(如JMeter)。 - **分阶段整**:每次仅整1-2个参数,观察效果。 --- #### **6. 常见面试题** 1. **JVM内存区域划分及作用?** 2. **如何选择垃圾收集器?CMS和G1的区别?** 3. **步骤和工具?如何分析OOM?** 4. **解释`-XX:NewRatio`和`-XX:SurvivorRatio`的作用?** 5. **G1的Region设计和Mixed GC过程?** --- #### **回答模板** > 在面试中可按照以下逻辑组织答案: > **1. 问题分析**:描述现象(如Full GC频繁)。 > **2. 工具使用**:如何用jstat/jmap定位问题。 > **3. 参数整**:具体化策略及原理。 > **4. 结果验证**:后GC频率/耗时的变化。 > **5. 经验总结**:强监控和代码化的重要性。 通过结合理论+实战,展现系统性能力!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值