JVM 垃圾收集与内存分配
判断对象是否还活着
引用计数法
给对象添加引用计数器,添加加1,引用失效减1,如果为0就是不可使用的。问题是不能解决互相引用带来的问题
可达性分析法
- 以GC Roots为起点,判断到一个对象是否有引用链,就是从开始节点向下能否搜索到,如果搜索不到就是不可达,可以被回收
- GC Roots有以下
- 虚拟机栈中的引用对象
- 方法区中的类静态属性的引用对象
- 方法区中的常量引用对象
本地方法栈是JNI(Native方法)的引用对象
什么是引用
- 就是reference类型中存储的数值代表另外一块内存中的起始地址就称这块内存代表着一个引用(侠义的引用)
- 强引用:类似Object obj=new Object()这类的,垃圾永不回收的引用对象 SoftReference
- 软引用:在内存发生溢出异常前,进行第二次回收的,如果回收后还不足,才会抛出溢出异常
- 弱引用: 能存活到下一次垃圾回收之前,与内存是否足够无关 WeakReference
虚引用:最弱唯一的目的就是在被回收时收到一个系统通知,不能通过引用获取对象和操作影响对象 PhantomReference
消除对象
一个对象至少要经历两次标记:如果不可达进行第一次标记并筛选是否要执行finalize()方法,当对象没有finalize()或被执行过都认为不需要执行。如果判断需要执行会把这个对象放在F-Queue队列中并在稍后虚拟机会以一个底线程去执行,所以这是对象自救的最后一次机会
回收方法区
- 判断一个类是否有用
- 类所有的实例都回收
- 加载类的ClassLoader已回收
- 对应的java.lang.Class对象没有任何地方被引用也无法通过反射访问该类的方法
是否回收类HotSpot虚拟机提供了-Xnoclassgc参数进行控制
垃圾回收算法
标记-清除法
- 标记阶段:慢
清除阶段 :慢,有内存碎片
复制算法
- 把内存一分为二(大小相等)当一块用完了,把存活的复制到另一块上
- 缺点:内存只用了一半:
优化:不分为相等的两部分而是分为Eden Survivor 默认比例8:1,当survivor不够时,老年代来担保,提醒 Survivor 分为From和To 每次复制完互换
标记-整理法
解决复制算法对象存活率高时的问题,先标记-然后让存活的向一端移动,以解新内存碎片的问题
分代收集算法
不同的代用不同的方法,针对性的回收
HotSpot实现
- 可达性分析:
- 因为分析准确所以要产生停顿,为了减少停顿,使用准确式GC ,就是虚拟机知道那些地主存着对象引用,使用OopMap数据结构来达到这个目的,这样GC直接扫描就可以了。
- 为了不产生大量的OopMap,只是在特殊的位置(安全点)记录这些信息,程序到了安全点才会停顿,考虑如果安全点少GC等的时间长,如果多大频繁。
- 在安全点时让所有的线程都到这个点,有两种办法一个是抢断式中断,就是所有的都停下来把那些不在安全点的继续运行到安全点,几乎没有用。另一个是主动式中断,就是打标记当线程到这个标记就自己产生中断(身陷)
- 安全区域
- 安全点不能解决程序没有获取CPU时无法产生中断的问题,以所以产生安全区域,就是此区域任何地方都是安全点
执行到安全区域时,标记进来了,然后发起GC,当要离开时如果没有完成根节点的枚举,等待,收到完成的信号后才可以离开
垃圾收集器
- Serial收集器
- 收集时必需暂停其它的所有线程
- ParNew 收集器
- 就是Serial收集器的多线程版本 控制参数与Serial一样,同样是目前能与CMS老年收集器一起使用的年轻代收集器
- 可以通过-XX:ParallelGCThreads来限制垃圾收集器的线程数
- Parallel Scavenge 收集器
- 并行多线程收集器 它的目标是达到一个可控的吞吐量=运行用户代码的时间/(用户代码时间+垃圾回收的时间)适用后始运逄面不需要太多交互的任务
- -XX:MaxGCPauseMills 垃圾停顿时间 大于0 的毫秒数时间短是以牺牲吞吐量和新生代的空间来换的
- -XX:GCTimeRatio 设置吞吐量大小(0-100)
- -XX:+UseAdaptiveSizePolicy 这是一个是否需要手动设置参数的开关,GC会自适应调整策略,但是要设置一个优化的目标就是上面两个参数
- Serial Old 收集器
- 单线程老年代收集器,使用标记-整理,当CMS收集器失败时使用
- Parallel Old 收集器
- 对应Parallel Scavenge收集器,因为Parallel Scavenge无法与CMS收集器一起工作,让吞吐量优化的收集器可以洛地使用
- CMS 收集器
- 是一种以获取最短停顿时间为目标的收集器 一般的b/s系统 上使用,以和用户线程一起工作
- 4个步骤
初始标记 :要停顿
并发标记
重新标记:要停顿
并发清除 - 缺点:对Cpu非常敏感,会占用用户资源
无法处理浮动垃圾 ,如果失败会产生Full GC ,如果运行内存不足会产生失败并用血腥和的Serial Old 进行回收
产生在碎片,如果空间不够时并提前触发Full GC 提供一个-XX:+UseCMSCompactAtFullCollection默认开,就是进行Full GC时整理内存碎片
-XX:CMSFullGCsBeforeCompaction 执行多少次不压缩整理后,执行一次内存整理,默认是0,每次都执行
- G1 收集器
- 前沿成果,生产环境中没有大量使用
并行与并发 分代收集 空间整合 可预测停顿(看书了解)
GC 日志
- GC , Full GC 停顿类型,如果手动调用System.gc()会产生Full Gc(System)
- [ 前数的数字是代表GC 发生的时间参考是虚拟机启动以来的秒数
- DefNew 新生代发生 ParNew 使用ParNew收集的新生代,PSYoungGen 是Parallel Scavenge对应的新生代
- Tenured 老年代 Perm 永久代 名称也与收集器对应
- a->b(c) d secs a是已使用的,b是已使用的 c是总容量 d 表示该区域GC使用的时间,单位是秒有的会给时更详细的时间
墙钟时间 包含阻塞时间
分配策略
优化分配在Eden上
- -XX:+PrintGCDetails 告诉虚拟机发生垃圾回收果打印回收日志
- Minor GC 新生代GC 频繁 速度快
Major GC/Full GC 老年代 比新生代慢10倍以上
大对象直接进入老年代
- 就是很长的字符串或者数组
- -XX:PretenureSizeThreshold 大于这个参数对象直接在老年代分配,只对Serial 和ParNew收集器有效
- -XX:MaxTenuringThreshold 晋升到老年代年龄设置
- 如果Survivor相同年龄的对象大小占总空间的一半,也直接进行老年代
如果有担保 那么如果空间不足会进行Full GC腾出更多的空间
** 参考深入理解Java虚拟机第三章 **
JVM 垃圾收集与内存分配的更多相关文章
- JVM(十一):内存分配
JVM(十一):内存分配 在前面的章节中,我们花了大量的篇幅去介绍 JVM 内的内存布局.对象在内存中的状态.垃圾回收的算法和具体实现等.今天让我们探讨一下对象是如何分配内存的. 堆内存划分 前面说过 ...
- 深入理解JVM(5)——垃圾收集和内存分配策略
1.垃圾收集对象 垃圾收集主要是针对堆和方法区进行. 程序计数器.虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收. 哪 ...
- Java Web 深入分析(12) JVM(2) 垃圾收集与内存分配
前言 java的内存分配和垃圾回收往往是影响系统性能和并发能力的主要因素,虚拟机提供许多的参数就是为了根据不同环境和请教下进行调优,没有最好的调优也没有固定的调优.需要我们深入的去了解jvm的各个垃圾 ...
- jvm(2):垃圾收集和内存分配
typora-root-url: ./ 垃圾收集 垃圾收集器关注的是线程共享的这部分内存. jvisualvm用来监控JVM的运行情况,可以用它来查看和浏览Heap Dump.Thread Dump. ...
- JVM读书笔记之垃圾收集与内存分配
1 概述 说起垃圾收集( Garbage Collection , GC ) ,大部分人都把这项技术当做 Java 语言的伴生产物.事实上, GC 的历史远远比 Java 久远,1960 年诞生于 M ...
- JVM学习之内存分配一
转自:http://blog.csdn.net/mazhimazh/article/details/16879055,多谢博主分享 我们知道计算机的基本构成是:运算器.控制器.存储器.输入和输出设备, ...
- JVM探秘:内存分配与回收策略
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. 内存分配一般关注的是对象在堆上分配的情况,对象主要分配在新生代的Eden区中,如果启用 ...
- 深入理解Java虚拟机二:垃圾收集与内存分配
垃圾收集:垃圾收集要完成三件事,包括哪些内存需要回收,什么时候回收及如何回收. 1.需要回收的内存判定:没有引用指向原先分配给某个对象的内存时,则该内存是需要回收的垃圾 Java垃圾收集器在对内存进行 ...
- JVM之---Java内存分配参数(第四篇)
1.内存分配参数---大纲 Ø如何设置堆内存 Ø如何设置栈内存 Ø如何设置方法区 Ø如何设置对的分配比率 Ø设置参数打印堆栈: ØJava程序的两种模式:Server&Client 2.设置堆 ...
随机推荐
- [C++]面向对象的程序设计——重要概念
1.面向对象程序设计的核心思想是数据抽象.继承和动态绑定.通过使用数据抽象可以将类的接口与实现分离:使用继承,可以定义相似的类型并对其相似的关系建模:使用动态绑定,可以在一定程度上忽略相似类型的区 ...
- FPGA 开发详细流程你了解吗?
FPGA 的详细开发流程就是利用 EDA 开发工具对 FPGA 芯片进行开发的过程. FPGA 的详细开发流程如下所示,主要包括电路设计.设计输入.综合(优化).布局布线(实现与优化).编程配置五大步 ...
- wait()与notify()
一,前言 简单画了一下线程的流程图,只是一个大概.如图所示,线程有多种状态,那么不同状态之间是如何切换的,下面主要总结关于wait()和notify()的使用. 二,wait() wait ...
- Redis 相关功能和实用命令(五)
慢查询原因分析 由于 Redis 是单线程的,它内部维护了一个命令队列,所以当有耗时的命令出现时,比如 keys *,后面的命令会被阻塞,通查查出慢查询可以对服务进一步优化. 设置慢查询阀值:默认10 ...
- maven war包打包去除jar包瘦身
1.pom文件配置 <!-- war包 --> <plugin> <groupId>org.apache.maven.plugins</groupId> ...
- springboot值mybatis 别名等配置
在application配置文件中添加如下: mybatis: #该配置替换在sql-config-map中的typeAliases配置 type-aliases-package: com.ww.ww ...
- POJ 2431——Expedition(贪心,优先队列)
链接:http://poj.org/problem?id=2431 题解 #include<iostream> #include<algorithm> #include< ...
- thinkphp5 模型表关联
student 表 外键 grade_idgrade 表主键 id在 模型中student表关联方法public function Grade(){ return $this->hasOne(' ...
- 使用Xhell连接Docker虚拟机
平时我们可以使用Xhell来连接Docker虚拟机. 1.首先,我们来用VirtualBox管理器来看一下default虚拟机的网络配置: 2.新建Xshell会话: a.我们可以看到ssh的主机IP ...
- [转] Julia 高性能动态编程语言入门
本文共 851字,阅读大约需要 3分钟 ! 概 述 Julia 是一个 "全新"的高性能动态编程语言,前两天迎来了其 1.0 正式版的重大更新.Julia集 Python.C.R. ...