Java内存结构及GC原理

Java内存结构及GC原理

我最想要了解的内容

  1. 内存结构,jvm由哪些部分组成?它们分别起到什么作用?

  2. GC什么时候发生?GC的日志如何查看?GC调优的依据是什么?如何判断 ?

JVM内存结构/布局

根据java8虚拟机规范,JVM内存结构,就是 Run-Time Data Areas ,运行时数据区域

jvm定义了6个运行时区域,

  • 程序计数器pc (program counter) register
  • jvm栈 jvm stack
  • 本地方法栈 native method stack
  • 堆 heap
    • java8虚拟机规范中这样描述:a heap that is shared among all Java Virtual Machine threads
  • 方法区 method area
  • 运行时常量池 Run-Time Constant Pool

从是否可被线程共享,可以分为

  • 线程私有: pc register,jvm stack,native method stack
  • 被所有jvm线程共享:heap,method area(包含运行时常量池)。

6个数据区域的作用

  • 程序计数器:

    • 每个线程都有自己的pc register,
    • 如果正在执行的方法不是native,那么程序计数器包含当前正在执行的java虚拟机(jvm)指令的地址
    • 如果线程当前正在执行的方法是native,那么jvm的程序计数器的值是undefined(即null)
    • 程序计数器的内存足够保存返回地址和本地指针,不会内存异常
  • jvm栈

    • 用于方法调用和返回,
    • 保存方法的局部变量和部分结果
  • native method stack(也称为本地方法栈,我觉得称为“本机方法栈”也合适)

    • 因为java8虚拟机规范中有这样一段描述:to support native methods (methods written in a language other than the Java programming language)
    • 存放所有类实例和数组
    • java8虚拟机规范中这样描述:The heap is the run-time data area from which memory for all class instances and arrays is allocated
    • 允许用户初始化大小,并控制最大最小值
  • 方法区

    • 类似于C语言中编译代码的存储区域或操作系统进程中的”text”段,
    • 存储每个类的结构,例如,运行时常量池,字段和方法,以及方法和构造函数的代码,还包括用于类和对象初始化及其接口初始化的特殊方法
    • 逻辑上是heap的一部分,同时java规范中仅规定一定要有这个data area,但是没有规定具体的实现,
    • 与heap一样允许用户初始化大小,并控制最大最小值
    • 可能抛出OOM
  • 运行时常量池
    运行时常量池是类文件(第4.4节)中constant_pool表的按类或按接口的运行时表示。
    它包含多种常量,从编译时已知的数字文字到必须在运行时解析的方法和字段引用。
    运行时常量池的功能类似于常规编程语言的符号表,尽管它包含的数据范围比典型的符号表还大。

问题:
可达性分析 需要分析与GC Roots的关联,那么对象产生是如何与GC Roots的关联的?什么时候失去与GC Roots的关联?

heap中,young generation 与old generation 中的各个区域默认分配多大内存空间呢?

GC原理

如何判断哪些对象是需要回收的垃圾对象?

两种常用的方法:

  1. 引用计数算法
    • 逻辑:在对象在中添加一个引用计数器,对象被引用,计数器+1,引用失效,计数器-1,统计计数器为0的对象视为需要回收的对象
    • 缺点:难以解决对象之间的循环应用,即A引用B,B引用A
    • 应用范围:微软COM技术,python
  2. 可达性分析算法
    • 逻辑:将GC Roots作为起点,通过起点向下遍历,走过的路径作为引用链,仅判定引用链包含的对象作为可达对象,不可达对象即为需要回收
    • GC Roots范围: 1. 虚拟机栈中引用的对象;2. 方法区中类静态属性引用的对象;3. 方法区中常量引用的对象;4. 本地方法栈中JNI引用的对象
    • 应用范围:主流jvm虚拟机

问题:关于循环引用的问题,如果A引用B,B引用A,这两个对象是否能被GC回收?
答:关键不在于A、B之间是否有引用,而是A、B是否可以一直向上追溯到GC Roots。如果与GC Roots没有关联,则会被回收,否则即可继续存活。

内存区域中哪些区域需要GC

  1. 不需要GC的:jvm线程独享的区域,pc register(程序计数器),jvm stack(jvm栈),native method stack(本地方法栈),其生命周期与线程相同(线程启动时创建,线程结束时销毁),不需要GC。

  2. 需要GC的:heap(虚拟机堆),method area(方法区),这两个数据区域,在jvm中是所有线程共享的,同时它们在虚拟机启动时创建,内存分配和回收具有不确定性。

    • 因为常量池在method area中,所以也需要GC

常见的GC算法

以Hotspot为例,来分析下GC的主要过程

垃圾收集器

【问题1】,标记-整理(/压缩)法,会让整理后的对象内存地址发生变化,那么暂定的线程是如何正常运行的?重启启动后重新获取对象的内存地址?

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022-2023 ligongzhao
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信