虚拟机(一):Java 篇

虚拟机(一):Java 篇

虚拟机(二):Android 篇


架构

运行时数据区:

栈:

堆:

  • 堆:通过new创建的对象都在堆中分配。OutOfMemoryError
    • TLAB(Thread Local Allocation Buffer,线程私有分配缓冲区)
  • 方法区:储了类代码和方法代码。OutOfMemoryError
    • 运行时常量池(Runtime Constant Pool)
  • 虚拟机栈:一个Java程序可能创建了多个线程,每个线程都会有自己的栈。StackOverflowError和OutOfMemoryError
    • 局部变量:方法参数和方法中定义的局部变量
    • 操作数栈:后入先出的栈
    • 动态连接:指向运行时常量池该栈桢所属方法的引用
    • 返回地址:当前方法的返回地址
  • 本地方法栈:本地方法(例如:C/C++语言)执行的区域。StackOverflowError和OutOfMemoryError
  • 程序计数寄存器:存储了执行指令的内存地址。无

判断对象引用

引用计数法:

  • 给对象添加一个引用计数器,每当被引用的时候,计数器的值就加一。引用失效的时候减一,当计数器的值为 0 的时候就表示该对象可以被 GC 回收了。
  • 引用计数无法解决循环引用问题:假设对象A,B都已经被实例化,让A=B,B=A,除此之外这两个对象再无任何引用,此时计数器的值就永远不可能为0,但是引用计数器无法通知gc回收他们

根搜索算法(可达性算法) GC Roots Tracing:

  • 通过一个叫 GC Roots 的对象作为起点,从这些结点开始向下搜索,搜索所走过的路径称为引用链,当一个对象没有与任何的引用链相连的时候则该对象就可以被GC 回收了。
  • 虚拟机中垃圾回收的根对象通常是下面这四种类型的对象
    • 栈中的local变量,即方法中的局部变量
    • 活动的线程(包括主线程和应用程序创建的子线程)
    • static变量
    • JNI中的引用

垃圾收集算法

  • 标记-清除算法:分为标记和清除两个阶段。该算法首先从根集合进行扫描,对存活的对象标记,标记完毕后,再扫描整个空间中未被标记的对象并进行回收。整个过程需要暂停整个程序的全部运行线程,让回收线程以单线程进行工作,过程结束再恢复运行线程。

    1. 效率问题。标记和清除过程的效率都不高。
    2. 空间问题。标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能导致,程序分配较大对象时无法找到足够的连续内存,不得不提前触发另一次垃圾收集动作。
  • 标记-整理算法:标记过程仍然与"标记-清除"算法一样,但不是直接对可回收对象进行清理。该算法在回收期间会同时将保留下来的对象移动聚集到连续的内存空间,从而避免内存空间碎片。但对象的移动是需要时间成本的。

  • 复制算法:

    • 该算法会将所拥有的内存空间分成两个部分。程序运行所需的存储对象先存储在其中一个分区中(例如:定义为"分区0")。算法执行过程中暂停整个程序的全部运行线程后,进行标记,然后将保留下来的对象移动聚集到另一个分区(例如:定义为"分区1"),这样便完成了回收。在下一次回收时,两个分区的角色对调。很显然,这种算法虽然避免了内存碎片,但对内存空间的使用是比较浪费的,因为始终只能有一半的空间用来使用。
    • 商业的虚拟机都采用复制算法来回收新生代。因为新生代中的对象容易死亡,所以并不需要按照1:1的比例划分内存空间,而是将内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间。每次使用 Eden 和其中的一块 Survivor。当回收时,将 Eden 和 Survivor 中还存活的对象一次性拷贝到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 空间。Hotspot 虚拟机默认 Eden 和 Survivor 的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80% + 10%),只有10%的内存是会被"浪费"的。特别地,当survivor1区也不足以存放eden区和survivor0区的存活对象时,就将存活对象直接存放到老年代。如果老年代也满了,就会触发一次FullGC,也就是新生代、老年代都进行回收。注意,新生代发生的GC也叫做MinorGC,MinorGC发生频率比较高,不一定等 Eden区满了才触发
    • "复制"算法在极端的情况下,会出现明显的问题,例如:某些很大的对象,它们的生命周期又很长,那么这些对象便会在分区之间来回移动,这显示是很耗时的。
  • 增量回收:该算法将所拥有的内存空间分成若干分区。程序运行所需的存储对象会分布在这些分区中,每次只对其中一个分区进行回收操作,从而避免程序全部运行线程暂停来进行回收,允许部分线程在不影响回收行为而保持运行,并且降低回收时间,增加程序的响应速度。

  • 分代收集算法

    • 新生代:每次垃圾收集时会有大批对象死去,只有少量存活,所以选择复制算法,只需要少量存活对象的复制成本就可以完成收集。
    • 老年代:对象存活率高、没有额外空间对它进行分配担保,必须使用"标记-清理"或"标记-整理"算法进行回收。
    • 永久代:用于涉及程序整个运行生命周期的对象存储,该空间通常不进行垃圾回收的操作。存储不变的类定义、字节码和常量等。
    • 通过分代,存活在局限域,小容量,寿命短的存储对象会被快速回收;存活在全局域,大容量,寿命长的存储对象就较少被回收行为处理干扰。
相关推荐
新手88602 小时前
Oracle VirtualBox虚拟机安装 和 安装 window11版本虚拟机 及 启用EFI和硬盘无法使用 问题
服务器·windows·计算机网络·安全·虚拟机
庞轩px4 小时前
HotSpot详解——符号引用、句柄池、直接指针的终极解密
java·jvm·设计模式·内存·虚拟机·引用·klass
漠北的哈士奇2 天前
VMware Workstation导入ova文件时出现闪退但是没有报错信息
运维·vmware·虚拟机·闪退·ova
村中少年5 天前
本地模型工具ollama配置使用openclaw指南
llm·nodejs·虚拟机·qwen·ollama·openclaw
DarkAthena6 天前
【ESXI】断电重启后NFS存储无法识别的修复方案
esxi·虚拟机·nfs
相思难忘成疾7 天前
《RHEL9虚拟机部署及SSH远程登录实践手册》
linux·运维·ssh·虚拟机
dlpay7 天前
vmbox虚拟机安装rknn-toolkit2,遇到illegal hardware instruction (core dumped) 需要avx指令支持
rknn·虚拟机·vmbox·rknntoolkit2·avx指令
【ql君】qlexcel7 天前
Vmware安装虚拟机出现此主机不支持64位客户机操作系统问题
ubuntu·vmware·虚拟机·不支持64位
语戚8 天前
从 JVM 底层拆解:i++、++i、i+=1、i=i+1 的实现逻辑与坑点
java·开发语言·jvm·面试·自增·指令·虚拟机
软件资深者9 天前
macOS Tahoe 26.3.1 ISO 虚拟机专用镜像:win系统/ESXi 服务器装苹果系统,改个后缀就能用
运维·服务器·macos·镜像·虚拟机