在<<Java编程思想>>书中,作者对垃圾回收的精要概述:"基于系统平台自适应的停止-复制"垃圾回收技术和"sun早期自适应的标记-清扫"垃圾回收技术。当然,对一个系统来说,初始化和清理是系统整个运行过程中大两大核心"进程",我觉得"初始化"和"清理"已经称为一种专业术语,不管是小段代码,一个大程序,一个系统,甚至是软件架构,在其本身构建和运行过程中,垃圾回收如同模拟现实世界场景一样,已称为一种模式,一种"行为"或是对象的"习惯"。
模拟现实场景来说,人是如何清理垃圾的,被丢弃的废纸,废品... 人会有专门的垃圾清理站或是保洁公司来处理这些“已耗尽”的能量,使其在土壤中循环再造。然而,这些垃圾也可以看做是"现实对象"。然而要模拟到用计算机实现这种垃圾回收系统,定是很有趣的事情,或许你早已在脑海中构建一副用计算机实现的垃圾回收场景,可那画面的内幕还是需要细细设计。于是有兴趣参考优化编程,java垃圾回收有向图等资料,简单地整理了一些基本的概念,分享之。若是很了解垃圾回收内幕的高手或是大师,还望你指点,我是这方面的新手,还在门前虚心求教和批评指正。
1. 垃圾回收
垃圾回收是Java程序设计中内存管理的核心概念,JVM的内存管理机制被称为垃圾回收机制。
一个对象创建后被放置在JVM的堆内存中,当永远不再引用这个对象时,它将被JVM在堆内存中回收。被创建的对象不能再生,同时也没有办法通过程序语句释放它们。即当对象在JVM运行空间中无法通过根集合到达(找到)时,这个对象被称为垃圾对象。根集合是由类中的静态引用域与本地引用域组成的。JVM通过根集合索引对象。
在做Java应用开发时经常会用到由JVM管理的两种类型的内存:堆内存和栈内存。简单来讲,堆内存主要用来存储程序在运行时创建或实例化的对象与变量。例如通过new关键字创建的对象。而栈内存则是用来存储程序代码中声明为静态或非静态的方法。
(1) 堆内存
堆内存在JVM启动的时候被创建,堆内存中所存储的对象可以被JVM自动回收,不能通过其他外部手段回收,也就是说开发人员无法通过添加相关代码的手段来回收堆内存中的对象。堆内存通常情况下被分为两个区域:新对象区域与老对象区域。
新对象区域:又可细分为三个小区域:伊甸园区域、From区域与To区域。伊甸园区域用来保存新创建的对象,它就像一个堆栈,新的对象被创建,就像指向该栈的指针在增长一样,当伊甸园区域中的对象满了之后,JVM系统将要做到可达性测试,主要任务是检测有哪些对象由根集合出发是不可达的,这些对象就可以被JVM回收,并且将所有的活动对象从伊甸园区域拷贝到To区域,此时一些对象将发生状态交换,有的对象就从To区域被转移到From区域,此时From区域就有了对象。上面对象迁移的整个过程,都是由JVM控制完成的。
老对象区域:在老对象区域中的对象仍然会有一个较长的生命周期,大多数的JVM系统垃圾对象,都是源于"短命"对象,经过一段时间后,被转入老对象区域的对象,就变成了垃圾对象。此时,它们都被打上相应的标记,JVM系统将会自动回收这些垃圾对象,建议不要频繁地强制系统作垃圾回收,这是因为JVM会利用有限的系统资源,优先完成垃圾回收工作,导致应用无法快速地响应来自用户端的请求,这样会影响系统的整体性能。
(2) 栈内存
堆内存主要用来存储程序在运行时创建或实例化的对象与变量。例如通过new关键字创建的对象。而栈内存则是用来存储程序代码中声明为静态或非静态的方法。
2. JVM中对象的生命周期
在JVM运行空间中,对象的整个生命周期大致可以分为7个阶段:
创建阶段;
应用阶段;
不可视阶段;
不可到达阶段;
可收集阶段;
终结阶段;
释放阶段
上面这7个阶段,构成了JVM中对象的完整的生命周期。
(1) 创建阶段
在对象的创建阶段,系统主要通过下面的步骤,完成对象的创建过程:
<1> 为对象分配存储空间;
<2> 开始构造对象;
<3> 从超类到子类对static成员进行初始化;
<4> 超类成员变量按顺序初始化,递归调用超类的构造方法;
<5> 子类成员变量按顺序初始化,子类构造方法调用。
在创建对象时应注意几个关键应用规则:
<1> 避免在循环体中创建对象,即使该对象占用内存空间不大。
<2> 尽量及时使对象符合垃圾回收标准。比如 myObject = null。
<3> 不要采用过深的继承层次。
<4> 访问本地变量优于访问类中的变量。
Java代码
1.比如:
2. for (int i = 0; i < 10000; i++) {
3. Object obj = new Object();
4. System.out.println(obj);
5. }
6.
7. 和
8. Object obj = null;
9. for (int i = 0; i < 10000; i++) {
10. obj = new Object();
11. System.out.println(obj);
12. }
比如:
for (int i = 0; i < 10000; i++) {
Object obj = new Object();
System.out.println(obj);
}
和
Object obj = null;
for (int i = 0; i < 10000; i++) {
obj = new Object();
System.out.println(obj);
}
这里修正一下,在绝对情况下,效率还是上面的要好, 因为后面的多了一条初始化语句。
而且各自作用域不同。 谢谢各位~~
(2) 应用阶段
在对象的引用阶段,对象具备如下特征:
<1> 系统至少维护着对象的一个强引用(Strong Reference);
<2> 所有对该对象的引用全部是强引用(除非我们显示地适用了:软引用(Soft Reference)、弱引用(Weak Reference)或虚引用(Phantom Reference)).
强引用(Strong Reference):是指JVM内存管理器从根引用集合出发遍历堆中所有到达对象的路径。当到达某对象的任意路径都不含有引用对象时,这个对象的引用就被称为强引用。
软引用(Soft Reference):软引用的主要特点是有较强的引用功能。只有当内存不够的时候,才回收这类内存,因此内存足够时它们通常不被回收。另外这些引用对象还能保证在Java抛出OutOfMemory异常之前,被设置为null。它可以用于实现一些常用资源的缓存,实现Cache功能,保证最大限度地使用内存你而不引起OutOfMemory。
Java代码
1.下面是软引用的实现代码:
2.
3. import java.lang.ref.SoftReference;
4. ...
5.
6. A a = new A();
7. ...
8.
9. // 使用a
10. ...
11.
12. // 使用完了a, 将它设置为soft引用类型,并且释放强引用
13. SoftReference sr = new SoftReference(a);
14. a = null;
15. ...
16.
17. // 下次使用时
18. if (sr != null) {
19. a = sr.get();
20. } else {
21. // GC由于低内存,已释放a,因此需要重新装载
22. a = new A();
23. sr = new SoftReference(a);
24. }
下面是软引用的实现代码:
import java.lang.ref.SoftReference;
...
A a = new A();
...
// 使用a
...
// 使用完了a, 将它设置为soft引用类型,并且释放强引用
SoftReference sr = new SoftReference(a);
a = null;
...
// 下次使用时
if (sr != null) {
a = sr.get();
} else {
// GC由于低内存,已释放a,因此需要重新装载
a = new A();
sr = new SoftReference(a);
}
软引用技术的引进使Java应用可以更好地管理内存,稳定系统,防止系统内存溢出,避免系统崩溃。因此在处理一些占用内存较大且生命周期较长,但使用并不繁地对象时应尽量应用该技术。提高系统稳定性。
弱引用(Weak Reference):弱应用对象与软引用对象的最大不同就在于:GC在进行垃圾回收时,需要通过算法检查是否回收Soft应用对象,而对于Weak引用,GC总是进行回收。Weak引用对象更容易、更快地被GC回收。Weak引用对象常常用于Map结构中。
Java代码
1.下面是弱引用的实现代码:
2.
3. import java.lang.ref.WeakReference;
4. ...
5.
6. A a = new A();
7. ...
8.
9. // 使用a
10. ...
11.
12. // 使用完了a, 将它设置为Weak引用类型,并且释放强引用
13. WeakReference wr = new WeakReference(a);
14. a = null;
15. ...
16.
17. // 下次使用时
18. if (wr != null) {
19. a = wr.get();
20. } else {
21. a = new A();
22. wr = new WeakReference(a);
23. }
下面是弱引用的实现代码:
import java.lang.ref.WeakReference;
...
A a = new A();
...
// 使用a
...
// 使用完了a, 将它设置为Weak引用类型,并且释放强引用
WeakReference wr = new WeakReference(a);
a = null;
...
// 下次使用时
if (wr != null) {
a = wr.get();
} else {
a = new A();
wr = new WeakReference(a);
}
虚引用(Phantom Reference): 虚引用的用途较少,主要用于辅助finalize函数的使用。
虚引用(Phantom Reference)对象指一些执行完了finalize函数,并为不可达对象,但是还没有被GC回收的对象。这种对象可以辅助finalize进行一些后期的回收工作,我们通过覆盖了Refernce的clear()方法,增强资源回收机制的灵活性。
在实际程序设计中一般很少使用弱引用和虚引用,是用软引用的情况较多,因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。
(3) 不可视阶段
当一个对象处于不可视阶段,说明我们在其他区域的代码中已经不可以在引用它,其强引用已经消失,例如,本地变量超出了其可视
的范围。
Java代码
1.try {
2. Object localObj = new Object();
3. localObj.doSomething();
4. } catch (Exception e) {
5. e.printStackTrace();
6. }
7.
8. if (true) {
9. // 此区域中localObj 对象已经不可视了, 编译器会报错。
10. localObj.doSomething();
11. }
try {
Object localObj = new Object();
localObj.doSomething();
} catch (Exception e) {
e.printStackTrace();
}
if (true) {
// 此区域中localObj 对象已经不可视了, 编译器会报错。
localObj.doSomething();
}
(4) 不可到达阶段
处于不可达阶段的对象在虚拟机的对象引用根集合中再也找不到直接或间接地强引用,这些对象一般是所有线程栈中的临时变量。所有已经装载的静态变量或者是对本地代码接口的引用。
(5) 可收集阶段、终结阶段与释放阶段
当一个对象处于可收集阶段、终结阶段与释放阶段时,该对象有如下三种情况:
<1> 回收器发现该对象已经不可达。
<2> finalize方法已经被执行。
<3> 对象空间已被重用。
分享到:
相关推荐
此外,由于历史原因,微软的JVM曾面临过与Java平台的互操作性和专利问题,这也是后来微软逐渐放弃自己JVM转而支持标准Java的一个原因。 尽管微软的x86 JVM已不再被广泛使用,但了解这段历史有助于我们理解Java...
【标题】"neo4j-graphql-java"是一个用于在Java虚拟机(JVM)环境中将GraphQL查询和突变转换为Neo4j Cypher语句的库。它旨在提供一种高效且无缝的方式,使得开发人员能够利用GraphQL的强大功能来操作图数据库——...
Java虚拟机(JVM)是Java程序运行的核心,它负责解释和执行字节码,为Java应用程序提供了一个跨平台的运行环境。JDK(Java Development Kit)包含了开发和运行Java程序所需的所有工具,包括JVM。当我们谈论"jdk,jvm...
JVM调优实战 本文档旨在介绍JVM调优实战的各个方面,包括JVM内存、垃圾回收、性能优化等。通过对JVM内存结构、垃圾回收机制和性能优化策略的详细讲解,帮助读者深入理解JVM的工作原理和优化方法。 1. JVM内存结构 ...
Java虚拟机(JVM)是Java程序运行的基础,它是一个抽象的计算机系统,负责执行Java字节码。本文将深入探讨JVM的启动过程及其基本原理。 首先,我们需要理解JVM的基本概念。JVM是Java Virtual Machine的缩写,它是...
JVM(Java Virtual Machine,Java虚拟机)是运行所有Java程序的假想计算机,是Java程序的运行环境,负责执行指令、管理数据、内存、寄存器等,是实现Java跨平台特性的关键部分。JVM指令手册详细记录了JVM的所有操作...
### JVM必知必会知识点梳理 #### 1. JVM的定义与层次 Java虚拟机(JVM)具有多重含义: - **一套规范**:即Java虚拟机规范,定义了Java虚拟机应该具有的行为。 - **一种实现**:例如HotSpot、J9、JRockit,它们都是...
### 深入解析JVM:Java虚拟机的精髓与挑战 #### JVM概览与重要性 JVM,即Java Virtual Machine(Java虚拟机),是Java程序员必须掌握的核心技术之一。初学者通常从简单的“HelloWorld”程序开始,逐渐接触更复杂的...
JVM(Java虚拟机)是Java语言运行的基础,它负责执行Java字节码,并且是Java跨平台特性的关键实现。JVM的主要职责包括加载Java程序、验证字节码、将字节码转换成机器码执行、内存管理、垃圾回收和提供安全机制等。...
"浅谈 JVM 原理" JVM(Java Virtual Machine)是一种虚拟机,它可以模拟完整的硬件系统功能,运行在一个完全隔离的环境中,提供了一个完整的计算机系统。JVM 可以分为三类:VMWare、Visual Box 和 JVM。其中,...
Java虚拟机(JVM)是Java程序运行的核心,它负责解释和执行Java字节码,为应用程序提供了一个跨平台的运行环境。`JVM指令手册`是深入理解JVM内部工作原理的重要参考资料,它详细列出了JVM所支持的所有操作指令,这...
Java虚拟机(JVM)是Java编程语言的核心组成部分,它为Java程序提供了运行环境,使得Java代码能够在不同的操作系统上“一次编写,到处运行”。JVM是Java平台的一部分,负责执行字节码,管理内存,垃圾收集,以及提供...
《深入JVM内核—原理、诊断与优化》是一份深度探索Java虚拟机(JVM)的视频教程,旨在帮助开发者全面理解JVM的工作机制,掌握性能诊断技巧,并能进行有效的优化。本教程覆盖了从基础到高级的JVM主题,不仅适用于Java...
《Java实现的JVM——深入理解与实践》 在计算机科学领域,Java虚拟机(JVM)是Java语言的关键组成部分,它使得Java程序能够在不同平台上运行而无需重新编译。本项目“jvmjava”是一个开源项目,由Java语言实现,...
### Java基础之JVM #### 一、JVM简介 **1.1 JVM是什么** Java Virtual Machine (JVM),即Java虚拟机,是Java技术的核心组成部分之一。它是一种抽象计算机,能够执行Java字节码(一种中间代码)的虚拟机环境。JVM...
JVM(Java虚拟机)是运行所有Java程序的假想计算机,是Java程序的运行环境。它在执行字节码时,解释成对应平台的机器码。JVM不仅能够提供Java程序的跨平台特性,还可以管理内存、堆栈、线程和垃圾回收等重要功能。 ...
JVM(Java Virtual Machine,Java虚拟机)是Java程序运行的基础,它负责将Java字节码转换为特定平台上的机器码,使得Java程序能够跨平台运行。JVM运行机制复杂且至关重要,涉及到内存分配、垃圾回收、类加载机制等多...
Java虚拟机(JVM)是Java程序运行的基础,它是一个抽象的计算机系统,负责执行Java字节码。本文将深入探讨JVM的工作原理,包括内存管理、类加载机制、垃圾回收以及性能优化等方面。 首先,我们来理解JVM的内存结构...