JVM内存分布和垃圾回收
2024-08-30 06:34:26
内存区域划分
- 程序计数器(Program counter Register)
- 描述 程序计数器(Program Counter Register)是一块较小的内存空间.它可以看作是当前线程执行的字节码的行号指示器
- 作用 线程切换之后能够恢复到正确的位置.
- 范围 线程私有,随线程而生,随线程尔灭
- 异常 此内存区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域.
- java虚拟机栈(Java Virtual Machine Stacks)
- 描述 虚拟机栈描述的是java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧,方法从调用到执行完成的过程,就对应栈帧入栈到出栈的过程.
- 存储内容
- 局部变量表
- 对象引用
- 基础数据类型
- 操作数栈
- 动态链接
- 方法出口
- 范围 线程私有,随线程而生,随线程尔灭
- 异常
- 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常.
- 虚拟机栈在动态扩展过程中无法申请到足够的内存,将会抛出OutOfMemoryError异常.
- 本地方法栈(Native Method Stack)
- 描述 本地方法栈与虚拟机栈所发挥的作用非常相似,他们之间的区别不过是虚拟机栈为虚拟机执行java方法服务,而本地方法栈则为虚拟机使用到的native方法服务.
- 范围 线程私有,随线程而生,随线程尔灭.
- 异常
- 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常.
- 虚拟机栈在动态扩展过程中无法申请到足够的内存,将会抛出OutOfMemoryError异常.
- java堆(Java Heap)
- 描述 java堆是虚拟机所管理的内存中最大的一块.也是垃圾收集器管理的主要区域.
- 作用 java堆是被所有线程共享的一块区域,虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存.
- 范围 线程共享.
- 异常 如果堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常.
- 方法区(Method Area)
- 描述 方法区和java堆一样,是各个线程共享的区域.别名(Non-Heap),目的应该是和java堆区分开.
- 存储内容
- 类信息
- 类名
- 访问修饰符
- 常量池
- 字面量
- 符号引用
- 静态变量
- 即时编译器编译后的代码
- 范围 线程共享
- 异常 当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常.
- 直接内存(Direct Memory)
- 直接内存并不是虚拟机运行时数据区的一部分.
- 异常 本机直接内存的分配不会受到java堆大小的限制,但是各个区域的内存总和大于物理内存限制时,将会抛出OutOfMemoryError异常.
垃圾回收(GC)
- 哪些内存需要回收?
- 需要回收 → java堆(重点) 和 方法区(永久代)
- 不需要回收 → 程序计数器 和 java虚拟机栈 和 本地方法栈
- 什么时候回收?
- 判断对象已死
- 引用计数算法 给对象添加一个引用计数器,每当有一个地方引用,计数器值就加1,引用失效时,计数器值就减1,计数器值为0就是该对象不可用.
- 优点 实现简单,效率高
- 缺点 不能解决对象之间的互相引用问题.
- 引用计数算法 给对象添加一个引用计数器,每当有一个地方引用,计数器值就加1,引用失效时,计数器值就减1,计数器值为0就是该对象不可用.
- 判断对象已死
- 可达性分析算法 这个算法的思路就是通过一系列的称为GCRoots的对象作为起始点,从这个节点开始向下搜索,搜素所走的路径称为引用链(Reference Chain) ,当一个对象到GCRoots没有任何引用链相连时,则证明此对象不可用.
- 引用
- 强引用 只要强引用还在,垃圾收集器永远不会回收掉被引用的对象.
- 软引用 描述一些还有用但并非必须的对象,系统将要发生内存溢出之前,将会把这些对象列入回收范围之中进行二次回收.
- 弱引用 用来描述非必须对象,被弱引用关联的对象只能生存到下一次垃圾收集发生之前.
- 虚引用 最弱的引用关系,一个对象是否有虚引用,完全不会对其生存时间有任何影响,也不可以通过虚引用来获取一个对象实例.
- 判生死 即使是在可达性分析算法中不可达的对象,也并非是非死不可,真正宣告一个对象死亡,至少要经理两次标记过程:
- 第一次标记: 根据可达性分析算法判断如果对象不可达,进行标记并且进行筛选,筛选条件是是否有必要执行finalize()方法,如果finalize()被虚拟机执行过,或对象没有覆盖finalize()方法时,,都会被认为没必要执行.
- 第二次标记: 如果第一次标记在筛选的时候,要执行finalize()方法,这是此对象的最后一次自救机会,如果执行完finalize()方法之后,此对象仍未逃脱,则此对象真的是要被回收了.
- 垃圾回收算法
- 标记 - 清除算法 首先标记处所有需要回收的对象,标记完成后统一回收所有被标记的对象.
缺点:
- 效率问题,标记和清除两个过程效率都不高.
- 空间问题,标记清除之后会产生大量的不连续的内存碎片,导致在分配较大对象时,无法找到连续的内存空间而不得不提前触发另一次垃圾收集动作.
- 复制算法 把内存划分为两块,每次只使用其中的一块,当此块内存使用完了,就把还存活的对象复制到另外一块上去,然后把已使用过的内存空间全部清理掉.
缺点 浪费了一半的内存空间.
- 标记 - 整理算法 首先标记出所有待回收的对象,然后让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存.
缺点 如果对象存活率较高,效率会很低.
- 分代收集算法
- 如何回收?
- Serial 收集器 这是一个单线程的收集器,它在进行垃圾回收的时候,必须要暂停其他所有的工作线程.
- ParNew收集器 Serial收集器的多线程版.
- Parallel Scavenge 收集器 更关注吞吐量 = 处理用户代码时间/(垃圾回收时间 + 处理用户代码时间)
- Parallel Old 收集器
- Serial Old 收集器
- CMS 收集器
最新文章
- Android ADB命令大全
- react 年-月-日 时:分:秒
- jQuery 常用的代码片段
- 向左对齐的Gallery
- <;<;编写可维护的JavaScript>;>;之避免使用全局变量
- C Primer Plus(第五版)7
- CentOS7区域设置
- 第二百一十九天 how can I 坚持
- PT100测温函数
- jquery方法详解
- js 常用方法记事本
- iOS 之 深复制、浅复制
- oracle sql生成临时递增数据
- 浅谈DP
- flask内容
- Linux(Debian) 上安装tomcat并注册服务开机自启动
- 微信公众号开发遇到simplexml_load_string 未定义
- Json转Scala对象一个问题
- Cookie机制和Session机制
- yarn的学习之2-容量调度器和预订系统
热门文章
- ASP.NET 知识点总结(六)
- 简单js图片点击向左滚动
- js实现浮动框跟随页面滚动,最后停留在原来位置
- linux mint 18.3设置分辨率死机问题的解决方法
- Android Error:Failed to resolve: com.afollestad:material-dialogs:
- PyCharm使用指南及更改Python pip源为国内豆瓣
- 了解Selenium与自动化测试第一天“云里雾里”
- RabbitMQ调用
- [leetcode]Add Two Numbers——JS实现
- python vars模块