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

一篇了解JVM

JVM一个在Java程序背后默默工作的人,任劳任怨,有实际使用情况




点击上方蓝字关注我们






JVM一个在Java程序背后默默工作的人,任劳任怨,有实际使用情况中有时需要针对程序对JVM进行一些设置,进行一些处理,而这也是本文要说的如果需要对JVM进行调优工作,我们首先需要了解JVM内存机制以及垃圾回收的机制



JVM中内存



jvm的内存图如下

程序计数器



内存空间小,线程私有。改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成

Java 虚拟机栈



栈,数据暂时存储的位置,先进后出的原则存储数据,线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表
操作数栈
动态链接
返回地址
,个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。

局部变量表:主要保存函数的参数以及局部的变量信息

操作数栈:一个后入先出栈,属于方法执行时的计算区域, 方法计算时字节码指令往操作数栈中执行入栈和出栈操作

动态链接:指向运行时常量池中该栈帧所属性方法的引用,持有这个引用是为了支持方法调用过程中的动态连接

返回地址:保存当前帧栈,方便恢复上层方法执行状态

本地方法栈

为本地方法提供服务,其中本地方法指的是操作计算机底层的一些代码,这部分代码并非使用Java编写,存储在本地

java堆



JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例数组。内部会划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。 由于现代 VM 采用分代收集算法, 因此 Java 堆从 GC 的角度还可以细分为: 新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代。

方法区/永久代



线程共享区域,存储包括类信息,类型常量池,字段信息,方法信息,类变量(也就是静态变量),类加载器信息,指向Class实例的引用,方法表

这里的类型常量池指的是类里面的常量,在类加载的时候会把把里面的内容放到方法区中的运行时常量池

在jdk7之前,HotSpot虚拟机使用的是永久代,方法区和永久代有本质上的不同,方法区是JVM标准,而永久代是JVM规范中的具体实现,并且只有HotSpot才拥有永久代,其他虚拟机没有。而在1.8版本中,移除了永久代,具体点说就是

JDK8 HotSpot JVM 移除永久代,使用本地内存来存储类元数据信息并称之为:元空间(Metaspace)

两者最大区别在于:元空间使用的是本地内存而不是JVM虚拟机。

另外注意在原来的JDK7这个版本中字符串常量池原本在永久代中,但是在后面JDK8中永久代被移除,所以这个时候常量池这个东西也就是从方法区移动到了Java堆中,这里注意注意:这里说的是字符串常量池,运行常量池包含字符串常量池,但是还有其他部分,1.8后字符串常量池移动到堆中,其他的还是在原地


一个对象的创建



在我们了解到JVM后,接下来我们说下是怎么运行这些内存的,创建一个对象步骤如下

1、当虚拟机收到一条new指令时,首先将检查当前new的类是否在常量池被加载过(在常量池找到需要new的类的符号,检查其是否被初始化过)。如果没有,说明类没有加载过,则执行相应的类加载过程;如果有则直接准备为新的对象分配内存。

2、把计算后的内存大小从内存中划取出来,内存的分配有两种

指针碰撞:

想象一个内存空间:左侧是已使用的内存区域,右侧是空闲内存区域,中间是指针来作为分界点的指示器。当我们分配内存时,只需要指针向右移动与对象所需内存相同大小的距离即可,所以称为“指针碰撞”

空闲列表:

当空闲内存区域和已使用内存区域相互交错时,虚拟机就需要维护一个列表,用来记录空闲内存块。当需要分配内存的时候,则需要找到一块足够大的内存区域分给对象实例,并更新表中的记录

3、线程安全问题,当在多线程情况下创建对象可能造成意外情况,所以这时候使用的不是上面的两种,而是新的方法,

4、初始化内存空间,把分配后的内存空间中的值初始化为0

5、设置对象必要参数,类的元数据信息,对象的hash码,GC年龄,锁相关

6、最后执行对象构造函数

简单点说流程就是:

检查有没有 ---》    开始分配内存 ----》 初始化值为零 ----》 添加对象必要参数 ----》 执行构造函数



垃圾回收机制


垃圾回收(GC)机制,JVM中一个面试以及工作中常看到的值,垃圾回收机制回收的就是不用的对象,以此来释放内存,增加软件的健壮性

3-1 标记对象



垃圾回收机制主要的操作区域就是堆和方法区,这里面如果要进行处理的话就需要先找到需要回收的对象,这里面主要使用发方法有

引用计数算法:堆中每个对象实例都有一个引用计数。当一个对象被创建时,就将该对象实例分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象实例的计数器+1),但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例的引用计数器减1。任何引用计数器为0的对象实例可以被当作垃圾收集。当一个对象实例被垃圾收集时,它引用的任何对象实例的引用计数器减1

可达性算法:程序把所有的引用关系看作一张图,从一个节点GC ROOT(根目录)开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点,无用的节点将会被判定为是可回收的对象。在Java中,虚拟机栈引用的对象,方法区中静态属性引用的变量,常量引用的对象,本地方法引用的对象不能作为GC ROOT

这里面的引用共分为强引用,软引用,弱引用,虚引用,引用的强度逐渐减弱

强引用:普遍存在的,直接通过new创建的,GC不会回收被引用的对象

软引用:还有用但并非必须的对象,在内存溢出异常之前会把这些对象进行回收

弱引用:描述非必须对象,只生存到下次垃圾收集发生前

虚引用:一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。它的作用是能在这个对象被收集器回收时收到一个系统通知。

3-2 开始回收

标记-清除算法

先扫描,对存活的对象进行标记,标记完成后扫描整个空间,然后回收没有标记的对象。好处是回收方便,坏处是会造成内存碎片

复制算法

为解决内存碎片的问题,把堆分成一个对象面或者多个 空闲面, 程序从对象面为对象分配空间,当对象满了,收集就从根集合(GC Roots)中扫描活动对象,并将每个 活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存

标记-整理算法

类似于标记清除算法,不同的是回收后会把剩余存活的对象那个向空闲空间移动,并更新指针,以此来解决内存碎片问题,但是会提高回收成本

分代回收算法

根据对象存活的声明周期把内存分为若干个区域,在JVM中堆分为两个区域:新生代,老年代。

其中新生代分为三块区域:Eden、From Survivor、To Survivor ,之间的比例是8:1:1 。

大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。

当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收。

老年代,可以理解经过多次垃圾回收仍然存在的对象,当老年代存满的时候出发Full GC

这里的Full GC 指的是对整个堆进行处理回收,共有四种情况导致Full GC

a) 年老代(Tenured)被写满;

b) 持久代(Perm)被写满;

c) System.gc()被显示调用;

d) 上一次GC之后Heap的各域分配策略动态变化;

除了Full GC出发之外还有一种执行,就是 Scavenge GC , Scavenge GC 是在Eden申请空间失败时触发,对Eden进行GC,清除非存活对象,并且把存活的对象移动到Survivor区。然后整理Survivor的两个区


扫描二维码获取

更多精彩







推荐阅读
  • 生产环境下JVM调优参数的设置实例
     正文前先来一波福利推荐: 福利一:百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。福利二 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 2018深入java目标计划及学习内容
    本文介绍了作者在2018年的深入java目标计划,包括学习计划和工作中要用到的内容。作者计划学习的内容包括kafka、zookeeper、hbase、hdoop、spark、elasticsearch、solr、spring cloud、mysql、mybatis等。其中,作者对jvm的学习有一定了解,并计划通读《jvm》一书。此外,作者还提到了《HotSpot实战》和《高性能MySQL》等书籍。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 初识java关于JDK、JRE、JVM 了解一下 ... [详细]
  • 一面自我介绍对象相等的判断,equals方法实现。可以简单描述挫折,并说明自己如何克服,最终有哪些收获。职业规划表明自己决心,首先自己不准备继续求学了,必须招工作了。希望去哪 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文介绍了Java虚拟机中的垃圾收集器,包括年轻代收集器Serial收集器、ParNew收集器、Parallel Scavenge收集器,以及老年代收集器Serial Old收集器、Parallel Old收集器和CMS收集器。对每种收集器的算法和特点进行了详细解析,希望对读者有参考价值。 ... [详细]
  • Spring Batch中多线程配置及实现例子
    本文介绍了在Spring Batch中开启多线程的配置方法,包括设置线程数目和使用线程池。通过一个示例演示了如何实现多线程从数据库读取数据并输出。同时提到了在多线程情况下需要考虑Reader的线程安全问题,并提供了解决方法。 ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
author-avatar
小乐的孤独人生_298
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有