第三章 JVM内存回收区域+对象存活的判断+引用类型+垃圾回收线程

注意:本文主要参考自《深入理解Java虚拟机(第二版)》

说明:查看本文之前,推荐先知道JVM内存结构,见《第一章 JVM内存结构

1、内存回收的区域

  • 堆:这是GC的主要区域
  • 方法区:回收两样东西
    • 无用的类
    • 废弃的常量
  • 栈和PC寄存器是线程私有区域,不发生GC

2、怎样判断对象是否存活

垃圾回收:回收掉死亡对象所占的内存。判断对象是否死亡,有两种方式:

  • 引用计数法

    • 原理:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值+1;引用失效时,计数器值-1
    • 实际中不用,不用的两个原因
      • 每次为对象赋值时,都要进行计数器值的增减,消耗较大
      • 对于A、B相互引用这种情况处理不了(这一点是不用的主要原因)
  • 可达性分析(跟踪收集)
    • 原理:从根集合(GC Roots)开始向下扫描,根集合中的节点可以到达的节点就是存活节点,根集合中的节点到达不了的节点就是将要被回收的死亡节点,如下图中的A/B/C是存活节点,D/E是死亡节点:

    • 根集合中的节点包括:简单来讲,就是全局性的引用(常量和静态属性)和栈引用(下边第一、三)

      • Java栈中的对象引用(存在于局部变量表中,注意:局部变量表中存放的是基本数据类型和对象引用)

        • 这是垃圾回收最多考虑的地方,所以有时,我们也会将死亡对象称为"没有引用指向的对象"
      • 方法区中:常量+静态(static)变量
      • 传到本地方法中,还没有被本地方法释放的对象引用

3、3种引用类型

  • 强引用(Strong Reference):A a = new A();//a是强引用
  • 软引用(Soft Reference):当内存不足时,释放软引用所引用的对象;当内存足够时,就是一个普通对象(强引用)
  • 弱引用(Weak Reference):弱引用对象只能存活到下一次垃圾回收之前,一旦发生垃圾回收,立刻被回收掉

4、方法区的回收

  • 废弃常量:例如,没有任何一个引用指向常量池中的"abc"字符串,则"abc"字符串被回收
  • 无用的类:满足以下三个条件
    • Java堆中不存在该类的任何实例
    • 加载该类的ClassLoader被回收
    • 该类的Class对象没有在任何地方被引用

注意:

  • 在实际开发中,尽量不用JSP去做前端,而是用velocity、freemarker这样的模板引擎去做
  • 与类相关常用的三个参数:
    • -XX:+PrintClassHistogram:输出类统计状态
    • -XX:-TraceClassLoading:打印类加载信息
    • -XX:-TraceClassUnloading:打印类卸载信息

5、垃圾回收线程

系统的垃圾回收是由垃圾回收线程来检测操作的,该线程是一个后台线程(daemon thread)。

5.1、后台线程与我们使用的前台线程而言,有一个特点:当JVM中的前台线程数量为0时,后台线程自动消亡。可以这样讲,后台线程依托于前台线程而存在。

5.2、垃圾回收线程为什么要设置成为后台线程呢?

我们想一下,当前台一个线程都没有时,垃圾还会有吗?或者说垃圾回收还有必要吗?答案是没有必要,所以此时垃圾回收线程也就失去了存活的意义。

所以可以这样讲,将一个线程是否设置为后台线程,就看这条线程在没有其他线程存在的情况下,是否还有存活的意义。

例如,在我们使用Apache mina2做RPC时,我们在消息的接收端直接开启一个后台线程启动服务来接受消息发送端发来的消息事件请求就可以。试着去想,如果在整个JVM中只有当前的这一个后台线程了,那么这个线程还有必要存活下来吗?当然没有必要,因为消息永远都不会再发送了(前台线程都没了)

时间: 2024-12-19 11:54:32

第三章 JVM内存回收区域+对象存活的判断+引用类型+垃圾回收线程的相关文章

JVM内存各个区域分工简单介绍

JVM内存各个区域简单介绍: 程序计数器:程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器. 在使用多线程时,为了线程切换后能恢复到正确的执行位置,每条线程都需要有个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为"线程私有"的内存.如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址:如果正在执行的是Native方法,这个计数器值则为空(Undefined). 此内存区域是唯一一个在Java

《java并发编程的艺术》读书笔记-第三章Java内存模型(二)

一概述 本文属于<java并发编程的艺术>读书笔记系列,第三章java内存模型第二部分. 二final的内存语义 final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.可以参照之前整理的关键字final.这里作者主要介绍final域的内存语义. 对于final域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序. 初次读一个包含final域的对象的引用,与随后初次读这

&lt;java并发编程的艺术&gt;读书笔记-第三章java内存模型(一)

一概述 本文属于<java并发编程的艺术>读书笔记系列,继续第三章java内存模型. 二重排序 2.1数据依赖性 如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性.数据依赖分下列三种类型: 名称 代码示例 说明 写后读 a = 1;b = a; 写一个变量之后,再读这个位置. 写后写 a = 1;a = 2; 写一个变量之后,再写这个变量. 读后写 a = b;b = 1; 读一个变量之后,再写这个变量. 上面三种情况,只要重排序两个操作的执行顺序,

JVM内存模型及对象在内存中初始化的过程

JVM内存模型 Java虚拟机所管理的内存区域,也称为运行时数据区,分为以下几个运行时数据区,如图所示 程序计数器:当前程序所执行字节码的行号指示器 程序计数器(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选 取下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等基础功能都需 要依赖这个计数器来完成. Java虚拟机的多线程是是通过线程轮流切

第三章 大网 OSPF多区域

实验步骤很简单,理论部分最重要!                      LSA通告 类型 发出 范围 内容 Router    LSA 1 区域内每个路由器 AREA 内部 通告每个路由器的链路状态和接口信息 Network  LSA 2 DR AREA 内部 DR到区域内部其他路由器的方式 汇总网络 LSA 3 ABR AREA 之间 通告区域外部路由器的到达方式 ASBR汇总LSA4 ASBR所在BDR发出 (每个AS 内的BDR) 除所在AS外的 所有AS 通告谁是ASBR AS 外部

(第三章)Java内存模型(中)

一.volatile的内存语义 1.1 volatile的特性 理解volatile特性的一个好办法是把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步.下面通过具体的示例来说明,示例代码如下: class VolatileFeaturesExample { volatile Long vl = 0L; //使用volatile声明64位的Long型变量 public void set(Long l) { vl = l; //单个volatile变量的写 } p

JVM调优总结(四)-分代垃圾回收详述

为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关,比如Http请求中的Session对象.线程.Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长.但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会比较短,比如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象甚至

JVM垃圾回收机制总结(4) :新一代的垃圾回收算法

全文转载: http://pengjiaheng.iteye.com/blog/548472 垃圾回收的瓶颈 传统分代垃圾回收方式,已经在一定程度上把垃圾回收给应用带来的负担降到了最小,把应用的吞吐量推到了一个极限.但是他无法解决的一个问题,就是Full GC所带来的应用暂停.在一些对实时性要求很高的应用场景下,GC暂停所带来的请求堆积和请求失败是无法接受的.这类应用可能要求请求的返回时间在几百甚 至几十毫秒以内,如果分代垃圾回收方式要达到这个指标,只能把最大堆的设置限制在一个相对较小范围内,但

JVM调优总结(五)-分代垃圾回收详述1

为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关,比如Http请求中的Session对象.线程.Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长.但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会比较短,比如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象甚至