System.gc()

最近在在翻看java的Garbage Collection,即大名鼎鼎的垃圾收集器GC的相关资料,整理了一下头绪,和朋友们共勉之。

Java的GC机制大名远扬,它大幅提高了程序员开发效率,省去了在c#中要显式的释放每一块内存的麻烦。我们常听到的“内存泄漏”实际上就是指无用的内存没有被及时回收。例如你声明了一个变量,而该变量所在的主进程需要运行很长时间,那么就形成了局部上的“内存泄漏”。“内存泄漏”是相对来说的,即在内存资源紧张的时候,无用的内存没有被回收,系统就会面临内存泄漏的危险。

那现在说下什么样的情况会被GC回收,说简单点就是通路断掉的内存会被回收。可以看下面例子:

Object o1 = new Object();
Object o2 = new Object();
o2 = o1;o2=o1
指明了这2个变量都指向了同一个对象,即使用了同一块内存区域,那么我们就说原o2申明的Object对象的那块内存会被GC回收,因为没有通路和它连通。

GC回收对程序员来说是透明的,要及时释放内存,最稳妥的方法就是在对象被使用完毕后,立即为该对象赋值为null,但是我们不知道什么时候这些无用资源会被回收,有什么办法可以显示执行吗?有的,就是显示调用System.gc();(该方法不保证立即会执行,因为不同的JVM使用不用算法来管理GC)。要让gc()达到立竿见影的效果,可以选择使用jdk1.2以来引入的4种对象引用类型上,废话不多说,看程序来说话:
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

class MyObject {
private String id;

public MyObject(String id) {
this.id = id;
}

public String toString() {
return id;
}

public void finalize() {
System.out.println("回收对象:" + id);
}
}

public class TestReferences {
public static void main(String[] args) {
// 创建强引用
MyObject ref = new MyObject("Hard");
System.out.println(ref);
ref = null;
System.gc();
System.out.println(ref);


// 创建软引用
SoftReference softRef = new SoftReference(
new MyObject("Soft"));
System.out.println(softRef.get());
System.gc();
System.out.println(softRef.get());

// 创建弱引用
WeakReference weakRef = new WeakReference(
new MyObject("Weak"));
System.out.println("before gc —— " + weakRef.get());
System.gc();
System.out.println("after gc —— " + weakRef.get());

// 创建虚引用
ReferenceQueue rq = new ReferenceQueue();
PhantomReference phantomRef = new PhantomReference(
new MyObject("Phantom"), rq);
System.out.println("before gc —— " + phantomRef.get());
System.gc();
System.out.println("after gc —— " + phantomRef.get());
}
}
输出如下:

Hard
null
Soft
Soft
回收对象:Hard
before gc —— Weak
after gc —— null
回收对象:Weak
before gc —— null
after gc —— null
回收对象:Phantom

以上我们创建了4种引用,依次是:强引用、软引用、弱引用、虚引用。

强引用即我们普通使用的申明方式,对于该引用,只有显示的赋值为null,gc才会视为回收对象。

软引用(SoftReference)是只有内存不足时,gc才会将它视为回收对象。

弱引用(WeakReference)是无论当前内存是否满足,gc都会去回收它。

虚引用(PahntomReference)实际是可以理解成“子虚乌有”的引用,目的仅仅是结合引用关联队列(ReferenceQueue),实现对对象引用关系的跟踪。

在 MyObject类中finalize方法中,我们让它在被回收时打印一句话出来,从输出结果来看,我们可以很容易的理解GC这4种对象引用的不同处理方式。从中我们可以得到结论,System.gc()可以对弱引用和虚引用达到立竿见影的效果。

好了以上一点小建议、想法,希望能对你有所帮助!


本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/yibunengjing/archive/2008/06/09/2526189.aspx
<think>好的,我现在需要帮助用户优化Java的System.gc(),也就是垃圾回收机制。首先,我得回忆一下用户的问题,他们想知道优化方法和最佳实践。用户可能遇到了性能问题,比如频繁的GC导致应用卡顿,或者想预防潜在的问题。 首先,我应该考虑System.gc()本身的问题。Java的System.gc()会显式触发Full GC,但这样做的缺点很多。比如,它会暂停整个应用,尤其是在使用Stop-The-World的回收器时,影响性能。而且,不同的垃圾回收器对System.gc()的处理可能不同,比如G1可能会忽略它,或者CMS会执行并发收集,但效果不一定好。所以,用户可能误用了这个方法,导致性能问题。 接下来,我需要整理优化方法。第一步通常是建议避免显式调用System.gc(),因为JVM自己管理GC更高效。然后,调整JVM参数是关键,比如堆内存大小,年轻代和老年代的比例,选择合适的回收器如G1或者ZGC。另外,优化代码,减少对象创建,使用对象池,及时释放资源,这些都能减少GC压力。 然后,最佳实践方面,监控和分析GC日志是必须的。用户需要知道如何启用GC日志,使用工具分析日志,找出频繁GC的原因。另外,选择适合应用场景的GC算法也很重要,比如低延迟选G1或ZGC,高吞吐量用Parallel GC。 还要考虑用户的引用中提到的内容,比如不同的垃圾回收器适用场景,性能优化中的内存管理和算法效率,以及监控系统运行状况的部分。需要将这些内容融入回答中,确保引用正确。 用户可能需要知道具体如何配置JVM参数,比如使用-XX:+DisableExplicitGC来禁用System.gc(),或者调整堆的大小。同时,代码层面的优化,比如避免内存泄漏,使用更高效的数据结构,这些也是关键点。 可能的问题点是,用户是否了解不同的GC回收器,或者如何监控GC活动。所以,生成的相关问题应该涵盖这些方面,比如如何选择GC算法,如何分析GC日志,或者内存泄漏的排查方法。 最后,确保回答结构清晰,分点说明,引用正确的来源,比如引用[1]提到的不同GC回收器,引用[3]中的监控指标。同时,避免使用Markdown,用自然的中文段落,符合用户的要求。</think>### Java System.gc()优化方法与最佳实践 #### 一、System.gc()的核心问题 1. **显式触发Full GC** `System.gc()`会强制触发完整的垃圾回收(Full GC),可能导致长时间的应用停顿(Stop-The-World)。例如,在使用串行垃圾回收器(Serial GC)时,暂停时间可能达到秒级[^1]。 2. **不可控性** 不同垃圾回收器对`System.gc()`的响应不同: - Parallel GC立即执行Full GC - G1 GC可能忽略此调用 - CMS GC可能触发并发标记阶段但无法保证及时回收[^1] #### 二、优化方法 1. **避免显式调用System.gc()** ```java // 典型错误用法示例 public void processData() { // ...业务逻辑 System.gc(); // 可能导致性能波动 } ``` 可通过JVM参数禁用显式GC: ```bash -XX:+DisableExplicitGC ``` 2. **优化JVM参数配置** - **堆内存设置** ```bash -Xms4g -Xmx4g # 固定堆大小避免动态调整 -XX:NewRatio=2 # 年轻代与老年代比例 ``` - **GC算法选择** ```bash # 低延迟场景(如Web服务) -XX:+UseG1GC -XX:MaxGCPauseMillis=200 # 大内存场景(>16GB) -XX:+UseZGC ``` 3. **代码层优化** - 使用对象池减少临时对象创建 - 及时关闭资源(数据库连接、文件流) - 避免在循环中创建大对象 - 使用`WeakReference`/`SoftReference`管理缓存 #### 三、最佳实践 1. **GC监控与分析** - 启用GC日志记录: ```bash -Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=100m ``` - 使用工具分析: - GCEasy(在线分析工具) - JVisualVM(本地监控) 2. **性能指标关注重点** | 指标 | 建议阈值 | 优化方向 | |---------------------|-------------------|------------------------| | Young GC频率 | <2次/秒 | 增大年轻代 | | Young GC耗时 | <50ms | 调整Survivor比例 | | Full GC频率 | 0次/小时 | 减少内存泄漏 | | Full GC最大耗时 | <1秒(G1/ZGC) | 升级GC算法 | 3. **环境变量配置建议** 根据引用[2]的建议: - 开发环境使用`JAVA_OPTS`设置通用参数 - 生产环境使用`CATALINA_OPTS`配置GC相关参数 ```bash CATALINA_OPTS="-Xmx4g -XX:+UseG1GC" ``` #### 四、典型问题排查流程 1. 通过`jstat -gcutil <pid> 1000`实时监控GC状态 2. 使用MAT(Memory Analyzer Tool)分析堆转储 3. 检查引用链确认内存泄漏(如图片未释放、未关闭的线程池) : 不同垃圾回收器的选择需根据应用特性决定,如G1适合大堆内存场景 [^3]: 系统应监控Young GC频率和对象晋升速率,避免过早提升到老年代[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值