"本文主要探讨了Sun JDK 1.5中的垃圾收集机制(GC),以及相关的内存优化策略。GC不仅负责内存回收,还参与内存分配决策。文章详细介绍了内存结构,包括栈、堆、方法区等,并讨论了内存分配的三个主要区域:堆分配、栈分配和堆外分配。此外,还解释了GC如何判断对象是否死亡,以及四种不同类型的引用(Strong、Soft、Weak、Phantom)及其在Full GC时的行为。最后,提到了Sun Hotspot对JVM堆采用分代策略的原因,主要是因为大部分对象生命周期短暂。"
在Java中,自动内存管理主要依赖于垃圾收集器(Garbage Collector,简称GC)。尽管GC能够自动回收不再使用的内存,但在高并发场景下,理解并优化GC的工作原理对于避免OutOfMemoryError(OOM)至关重要。Sun JDK 1.5的GC触发机制和并行Minor(年轻代)Mark-Sweep-Compact(MSC)过程相同,这在旧生代GC中尤其明显。
内存结构方面,JVM主要由以下几个部分组成:
1. **程序计数器(PC Register)**:存储当前线程的下一条指令地址。
2. **虚拟机栈(JVM Stack)**:每个线程拥有一个独立的栈,包含多个栈帧,用于存储局部变量区、操作数栈和动态链接。
3. **本地方法栈**:与虚拟机栈类似,但服务于JNI调用的本地方法。
4. **堆(Heap)**:所有对象实例的存储区域,分为新生代和老年代,新生代又细分为Eden和两个Survivor空间。
5. **方法区(Method Area)**:存储类信息、常量、静态变量等。
6. **元数据区( PermGen/元空间)**:在JDK 8之前是永久代,之后是元空间,用于存储类装载的信息。
内存分配策略:
- **堆分配**:大多数对象在Eden区分配,少数直接进入老年代。为了优化分配速度,引入了TLAB(Thread Local Allocation Buffer)技术,使得每个线程有自己的内存分配缓冲区。
- **栈分配**:基本数据类型的局部变量和通过Escape Analysis后标量替换的局部对象直接在栈上分配。
- **堆外分配**:例如DirectByteBuffer,或者通过Unsafe类直接分配,但这不推荐,因为可能导致内存泄漏。
GC判断对象死亡的标准是对象是否可达。Hotspot将引用分为四种类型:
- **Strong**:常规引用,只要存在就不会被GC。
- **Soft**:软引用,只有在内存不足时才会被GC,可配置`-XX:SoftRefLRUPolicyMSPerMB`调整其存活时间。
- **Weak**:弱引用,只要GC发现就会回收,回收后放入`ReferenceQueue`。
- **Phantom**:幻引用,对象已经不可达,但在Finalization Queue中,GC会在对象从堆中彻底释放后通知。
Sun Hotspot采用分代收集策略,主要是因为大多数对象的生命周期很短,新生代GC能有效处理这些临时对象,减少Full GC的发生,从而提高系统性能。通过调整JVM参数如 `-Xms`、`-Xmx`、`-XX:PermSize` 和 `XX:MaxPermSize`,可以控制内存大小和分配策略,以适应不同应用的需求。同时,理解和分析GC日志,可以找出可能的性能瓶颈,进行进一步的调优。