热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JVM——垃圾收集器与内存分配

1.概述本章讲述的是JVM的内存分配和回收首先我们清楚,Java的内存区域主要有五个:程序计数器,虚拟机栈,本地方法栈,堆和方法区。然而前三个都是线程私有的,随着线程的创建而创建,











1.概述

:fast_forward:本章讲述的是JVM的内存分配和回收
首先我们清楚,Java的内存区域主要有五个:程序计数器,虚拟机栈,本地方法栈,堆和方法区。然而前三个都是线程私有的,随着线程的创建而创建,消亡而消亡,栈中每一个栈帧分配的大小也是确定的(类加载完成后也就确定),即方法结束或者线程消亡的时候内存也就跟着回收了,不必担心太多。
但是,堆和方法区的分配却具有明显的不确定性,因为你必须在程序运行期间才能知道具体分配多少内存,所以Java的垃圾收集器关注的就是堆和方法区!


2.死亡对象

ok,既然要做垃圾回收,那么其对象就是那些已经死亡的对象,ok那我们如何判断对象死亡?

:boom: 2.1引用计数法
很简单,就是给每个对象增加一个引用计数器,如果其他地方有引用这个对象,那么就将其计数器加一;引用失效的时候就减一;任何时候如果垃圾收集器发现某对象的引用计数器为0,就代表这个对象已经死亡,可以回收!
:+1:优点:简单高效
:-1:缺点:计数器占用了一些额外的内存,重点是需要大量的额外处理才能保证正确的工作,譬如说循环引用问题!


既然谈到了引用我们不妨说下Java中的引用概念,主要有四种:



  • 强引用,普遍存在的,例如最经常的 “Object obj = new Object();”代码,即只要强引用关系还在,垃圾回收器就永远不会回收这些被引用的对象
  • 软引用,描述一些还有用但非必须的对象,在发生oom之前,会对这些软引用的对象进行二次回收,如果还不行只好抛出oom
  • 弱引用,强度更弱, 但凡让垃圾回收器碰到必定回收!
  • 虚引用,最弱了,根本不影响对象的生存情况,唯一用来将这个对象回收时会受到一个系统通知

:boom:2.2可达性分析法
可达性分析算法是目前主流的判断对象死亡的算法,此算法主要是以一系列称为“GC Roots”的跟对象作为起点,向下遍历搜索走过的路径,这些路径被称为引用链!如果某个对象到GC Roots没有任何引用链相连,那么称这个对象不可达!即判定其为死亡!
:exclamation:GC Roots



  • 虚拟机栈中引用的对象(栈帧中的本地变量表)
  • 本地方法栈中JNT(即常说的native方法)引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 所有被同步锁持有的对象

3.真正死亡?

:warning:难道对象在可达性分析算法中不可达,就说明其一定必须死亡吗?
不一定!不可达对象还处于“缓刑”阶段,即要真正判断一个对象死亡,至少要经历两次标记过程!
:clock1:第一次标记:当对象不可达时进行一次标记
:clock2:筛选:从这些标记中进行筛选,检查是否有必要执行finalize方法!如果重写了并且没有被调用过,ok,将放置在一个F-queue队列,然后由虚拟机的一条finalizer低优先级线程去执行它,而且还不一定执行成功。否则就是不必要执行
:clock4:第二次标记:从F-queue队列中检查,如果对象成功自救,ok你活了下来,否则真正回收


4.回收方法区

垃圾收集器的工作区域大部分都集中在堆,对于方法区的回收也有一定的规范,只不过性价比不高,但还是要强调一下
收集的对象是:废弃的常量和不再使用的类型!!
:boom:在大量使用反射,动态代理等字节码的框架,通常都需要Java虚拟机具备类型卸载的能力,以保证不会对方法区造成过大的内存压力!


5.垃圾收集算法

5.1 分代收集理论



  • 弱分代假说
  • 强分代假说
  • 跨代引用假说

5.2 标记-清除算法

:thumbsup:简单易实现
:thumbsdown:



  • 执行效率不稳定,如果存在大量被回收对象则需要进行长时间的标记
  • 空间利用率低下,因为标记清除这种算法会产生大量的内存碎片,导致之后如果有较大对象在新生代分配不到内存而提前触发一次垃圾收集

5.3 标记-整理算法

:thumbsup::空间利用率高,不会产生内存碎片
:thumbsdown::移动负担较重,需要更新存活对象引用,甚至或造成长时间用户线程的”Stop The World”但很短,最关键的是低停顿!


5.4 复制算法

:thumbsup::实现简单,运行高效
:thumbsdown::浪费空间,毕竟另一半survivor区是不可用的。


IBM公司之前做过研究,提出新生代中有98%的对象都熬不过第一轮收集的,所以没必要将新生代的内存空间划分为一比一。现在HotSpot虚拟机大都也不会采取这种划分,更多的是将eden区和survivor区划分为8:1



6. 垃圾收集器

话不多说先上一副图,如果两个收集器之间有连线,说明他们之间可以搭配使用
JVM——垃圾收集器与内存分配


6.1 Serial收集器

最基础的一款垃圾收集器,是一款单线程的垃圾收集器,他强调在垃圾收集的过程中,必须暂停其他线程的工作,直到收集结束。

JVM——垃圾收集器与内存分配
—————————————Serial/Serial Old————————-
优点:简单而高效(单线程嘛,没有线程交互的开销),消耗内存少
缺点:”Stop The World”时间较长,用户体验差!


虽然用户体验恶劣,早期hotspot虚拟机设计者表示十分委屈:“你妈妈在给你打扫房间的时候,肯定也会让你老老实实的坐在凳子上,如果她一边打扫,你一边扔纸屑,什么时候能打扫完!!!”



6.2 ParNew收集器

其实就是Serial收集器的多线程并行版本,在单核处理器下并不比Serial收集器有多大优势,但是在多核环境下有着明显的优势

JVM——垃圾收集器与内存分配
—————————————ParNew/Serial Old——————————–


6.3 Parallel Scavenge收集器

和ParNew非常相似,但是关注点不同,ParNew和CMS收集器重点关注如何缩短垃圾收集时用户线程的停顿时间,而这款主要关注吞吐量!

用户执行代码的时间
吞吐量 = ——————————————————————————————————
用户执行代码的时间 + 垃圾收集的时间

6.4 CMS收集器

JVM——垃圾收集器与内存分配
CMS收集器是一款以获取最短停顿时间的垃圾收集器,主要包括四个过程



  1. 初始标记 : 很快
  2. 并发标记 :与用户线程并发执行
  3. 重新标记 :修正并发标记期间用户线程的不一致性
  4. 并发清除 :与用户线程并发执行

优点:第一个真正意义上的并发收集器,虽然也需要”Stop The World”但很短,最关键的是低停顿!!!
缺点:



  • CMS对处理器资源十分敏感
  • 无法处理浮动垃圾,有可能出现失败而导致一次完全的Full GC出现!
  • 内存碎片严重,会给内存分配带来巨大压力!

6.5 Garbage First收集器

JVM——垃圾收集器与内存分配

同样包括四个过程:



  1. 初始标记(Initial Marking)
  2. 并发标记(Concurrent Marking)
  3. 最终标记(Final Marking)
  4. 筛选回收(Live Data Counting and Evacuation)

:boom: G1收集器的优势:



  • 并行与并发


  • 分代收集


  • 空间整理 (标记整理算法,复制算法)


  • 可预测的停顿(G1处理追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒)



使用G1收集器时,Java堆的内存布局是整个规划为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region的集合。
G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在真个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获取的空间大小以及回收所需要的时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage-First名称的又来)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽量可能高的回收效率





JVM


推荐阅读
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 本文介绍了一道经典的状态压缩题目——关灯问题2,并提供了解决该问题的算法思路。通过使用二进制表示灯的状态,并枚举所有可能的状态,可以求解出最少按按钮的次数,从而将所有灯关掉。本文还对状压和位运算进行了解释,并指出了该方法的适用性和局限性。 ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
author-avatar
磊磊860219
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有