堆内存和设置GC

JVM通过Ergonomics技术已经尽可能的让jvm不要我们去操心底层的细节,而尝试提供给我们好的服务。
但是,内存管理和gc并没有一个一劳永逸的方案。
GC有可能成为性能的瓶颈。很多时候还是要程序员自己动手去做一些调优。
以下简要介绍一些关键概念。

JVM会自动选择使用server mode还是client mode。但是我们一样可以手工设置。
java -server -client

JVM的内存管理分为堆内存(Heap Memory)和非堆内存。
Heap Memory用来存储大部分对象。
非堆内存=Code Cache+Permanent Generation。
其中Code Cache用于编译和保存本地代码(native code)的内存
Permanent Generation保存虚拟机自己的静态(refective)数据,例如类(class)和方法(method)对象。

经过统计,大部分的内存垃圾都是刚刚new出来的对象产生的,于是,Heap Memory的内存管理是分代的。
JVM的堆内存划分为Young和Tenured。Young里面有1个Eden和2个Survivor,其中一个Survivor永远为空。
按照代的从新到老的顺序:Eden,Survivor,Tenured.

Heap Memory=Eden space+ 2个Survivor space+Tenured space。

为什么Survivor有两个呢.
其中一个一直为空.
大部分对象的分配是在Eden中进行的。当进行一次gc时,可以把Eden和Survivor中的live object复制到那个空的Survivor.

可以用设置标志来查看gc的运行情况.(-verbose:gc)
这个会在console中打出如下信息
[GC 325407K->83000K(776768K), 0.2300771 secs]

GC代表这是一次Minor collection,只回收Young中的对象。
Full GC代表一次Major collection,回收Tenured。

和gc相关的性能指标

Throughput 程序真正运行时间/(程序真正运行时间+GC时间)
Pauses GC导致的程序暂停时间

常见的GC,有多种GC可供我们选择.

serial collector:
单线程GC.

parallel collector:
并行GC,多线程,如果机器是多核的比较适合.
传统的parallel collector同时只能有一个线程作Major collection.
可以引入parallel compaction,多个线程并行做Major collection.

concurrent collector:
该GC大部分的工作都是和程序并行完成的,所以Pauses的时间比较少.


如何设置GC.

0 大部分情况不用调用gc,让jvm自己做好了.
1 任何时候都是让jvm先自己选择gc,当性能有问题的时候再手工调.
2 当有Pauses时间要求的时候,尝试concurrent gc.
3 当没有Pauses时间要求时,尝试parallel collector.
4 合理的设置gc的其他参数以及堆的其他参数.
5 不要迷信任何主观的想法,一定要测试,比较,修改,测试,比较,修改...的坐下去,直到性能在合理的期望中.
6 server mode时内存的划分反向了,用jsonsole可以观察到,设置参数时需要注意.
### Java 堆内存减少是否由垃圾回收(GC)引起 Java 堆内存的减少通常与垃圾回收(GC)密切相关。当堆内存中的对象不再被引用时,垃圾回收器会回收这些对象所占用的内存空间,从而导致堆内存的减少。以下是对该问题的详细分析: #### 1. 判断堆内存减少是否由 GC 引起 可以通过以下工具方法来判断堆内存减少是否由 GC 引起: - **jstat**:使用 `jstat -gc <pid>` 命令可以查看 JVM 的垃圾回收统计信息,包括 Minor GC Full GC 的次数及耗时[^3]。如果发现 GC 次数增加且堆内存随之减少,则可以初步判断堆内存减少是由 GC 引起的。 - **jmap**:通过 `jmap -heap <pid>` 命令获取当前 JVM 堆的详细信息,包括新生代、老年代永久代的容量及使用情况[^3]。如果观察到某些代区的使用量下降,则可能是 GC 的结果。 #### 2. 使用 jstack 分析线程状态 虽然 `jstack` 主要用于生成线程快照并分析线程状态,但它也可以间接帮助判断 GC 是否发生。例如: - 在生成的线程堆栈信息中,可以搜索与 GC 相关的线程名称(如 `G1 Main Marker` 或 `Concurrent Mark-Sweep`),以了解 GC 线程的活动情况[^2]。 - 如果发现多个线程处于等待状态(WAITING 或 BLOCKED),并且这些线程与 GC 线程相关联,则可能表明 GC 正在进行或刚刚完成。 #### 3. 动态开启 GC 日志 为了更精确地确认 GC 是否触发以及其对堆内存的影响,可以动态开启 GC 日志: ```bash jinfo -flag +PrintGCDetails <pid> ``` 此命令无需重启 JVM 即可启用详细的 GC 日志输出,日志中会记录每次 GC 的类型、时间、回收前后的堆内存使用情况等信息[^1]。 #### 4. 示例代码 以下是一个简单的脚本,用于监控 GC 活动并记录堆内存变化: ```bash #!/bin/bash PID=$1 if [ -z "$PID" ]; then echo "Usage: $0 <pid>" exit 1 fi echo "Enabling GC logging..." jinfo -flag +PrintGCDetails $PID echo "Monitoring heap usage..." while true; do jstat -gc $PID | awk '{print $NF}' # 输出堆内存使用情况 sleep 5 done ``` #### 5. 注意事项 - 在生产环境中使用上述工具时需谨慎,避免因频繁调用命令而导致系统性能下降。 - 如果怀疑存在内存泄漏问题,可以结合 `jmap` 内存分析工具(如 MAT)进一步排查[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值