后端开发 java_Java后端开发三年,你不得不了解的JVM

JAVA程序员,三年是个坎,如果过了三年你还没有去研究JVM的话,那么你这个程序员只能是板砖的工具了。下面来个JVM的解析可好?

JVM是Java Virtual Machine(Java虚拟机)的缩写,也就是指的JVM虚拟机,属于是一种虚构出来的计算机,在我们实际的电脑上来进行模拟各种计算机的功能的这么个东西。

因为有了JVM的存在,搞JAVA的不再需要去关心什么时候去释放内存,也不会像C++程序员那样为了一点点内存而惆怅,对就是你,JVM虚拟机帮你把这些东西都完成了,那么我们来说说JAVA的JVM吧!

我们先来看看JVM的模型吧,之前在百度上看文档,上面就说了几个,方法区,堆,栈,计数器。没了,很难受,于是看了深入理解JVM的书,也算是有点体会。

在深入理解JVM一书中提到,JVM运行时的数据区域会划分为几个不同的区域,有方法区(Method Area),虚拟机栈(VM Stack),本地方法栈(Native Method Stack),堆(heap),程序计数器(Program Counter Register),下面就是书中的图:

format,png

咱们一个一个来解释: 先说程序计数器(Program Counter Register):程序计数器实际上就是用于存放下一条指令所在地址的地方,当我们执行一条指令的时候,要先知道他存放的指令位置,然后把指令带到寄存器上这是就是获取指令,然后程序计数器中的存贮地址会加1,然后这样子循环的去执行,而且程序计数器这个小的内存区是“线程私有的内存”。

为什么会是私有的呢?,在深入理解JVM一书中说的是虚拟机的多线程通过线程的轮流切换来切换分配处理器的执行时间的方式来实现,说起来其实很拗口的,其实也就是说一个处理器,同一个时刻,只会执行一个线程的指令,但是时间可能不均衡,可能第一分钟在a线程,第二分钟就去执行b线程了,但是呢,为了保证切换回来还需要是一致的,那么每个线程中就会有一个独立存在的程序计数器,独立来存贮,为了保证不影响。所以他是一个“线程私有的内存”。

程序计数器还有几个特点:

如果线程正在执行的是Java 方法,则这个计数器记录的是正在执行的虚拟机字节码指令地址。

如果正在执行的是Native 方法,则这个计数器值为空(Undefined)。

此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

分别解释一下这三句话吧,这是深入理解java虚拟机中的原话,第一句好像已经很直白了,没的说,来说说第二句话吧

因为这个计数器记录的是字节码指令地址,但是Native(本地方法);就比如说(System.currentTimeMillis())他是通过C来实现,直接通过系统就能直接调用了不需要去编译成需要执行的字节码指令的话,那么就相当于不过程序计数器,它没有记录的话,那他的计数器的值就肯定为空了。

第三句话 我们可以试试编译一小段代码,然后反编译出来看看

format,png

也就是实际上是这个样子的

public class Test{ public int test(){ int a = 10; //0 ...... int b = 20; //3....... int c = 30; //6...... return (a+b)*c; //11.... 13.... 14...执行加减乘除操作 } }

上面的0,2,3,5,6,8....就是指令的偏移地址bipush就是入栈指令, 在执行到test方法的时候,线程就会创建对应的程序计数器在计数器中放0,2,3,5,6,8....这些指令地址,所以计数器里改变的不是内存的大小,它也就没有溢出了。

下面我们再来说一下:JAVA虚拟机栈(VM Stack)

线程私有,生命周期和线程一样,这个虚拟机栈描述的是JAVA方法执行的内存模型,用于存局部变量,操作数栈,方法出口等信息的,上面那个bipush就是入栈指令,在这里最需要注意的就是他存放的是什么数据.局部变量里面放的就是那些我们所知道的基本的数据类型,对象引用的话那就是一个地址。

在虚拟机规范里面还说,他的2个异常状况:

一个是StackOverflowError异常,栈内存溢出,这肯定很容易理解,就是栈的内存不够,你的请求线程太大。(固定长度的栈)

如果说在动态扩展的过程中,申请的长度还是不够,那么会抛出另外一个异常OutOfMemoryError异常。

本地方法栈(Native Method Stack) :

它和虚拟机栈很类似,区别就在于虚拟机栈执行的是JAVA方法,但是本地方法栈则是Native方法,其他的没啥不同就连抛出异常都一样的。

JAVA堆(heap)

在JVM一书中也有提到,Heap是在JAVA虚拟机中内存占用最大的一个地方,也是所有线程共享的一个内存区域,堆内存中主要就是用于存放对象实例的。

几乎是所有的对象实例都在这里分配内存,JAVA堆是垃圾收集器管理的主要区域,那么现在重点来了,面试中问到最多的垃圾回收机制接下来就要仔细说说了。

内存回收,现在都是进行的分代算法,堆中也是,新生代,老年代,而且两种垃圾回收机制是采用的不同的回收机制的,在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用"标记-清理"或"标记-压缩"算法来进行回收,说回收机制先看看heap的分区(这个from和to 并不是绝对的,看对象处在哪个位置,GC的次数不一样之后,那from和to会有相应转变)

format,png

分区一目了然,下面研究一下算法实现吧

Minor GC:

GC新生代,

Full GC:

老年代GC,

因为新生代中对象的存活率比较低,所以一般采用复制算法,老年代的存活率一般比较高,一般使用”标记-清理”或者”标记-整理”算法进行回收。

看了有几天才明白啥意思,我说说我自己的见解吧,还是画图吧,

Minor GC:

我们每次new对象的时候都会先在新生代的Enden区放着也就是最开始 是这样子的

format,png

然后在Enden用完的时候里面会出现待回收的

format,png

然后就来了把存活的对象复制放到Survior1(from)中,待回收的等待给他回收掉 就是这样的

format,png

然后把Enden区清空回收掉

format,png

这样的话 第一次GC就完成了,下面再往下走

当Enden充满的时候就会再次GC

先是这个样子的

format,png

然后会把 Enden和Survoir1中的内容复制到Survior中,

format,png

然后就会把Enden和Survior进行回收

format,png

然后从Enden中过去的就相当于次数少的,而从Survior1中过去的就相当于移动了2次

format,png

这样新生代的GC就执行了2次了,

当Enden再次被使用完成的时候,就会从Survior2复制到Survior1中,

接下来是连图

format,png

经过回收之后Surior1就变了,1对象是从Enden直接复制过来的,2对象是Enden-->Survior2-->Survior1 ,3对象则是从Enden-->Surivior1-->Survior2-->Survior1 复制过来的,这样一步一步的执行下去的时候,就是新生代的GC。

既然这样,那为什么还会存在老年代呢?其实如果GC在执行的时候有些对象一直没有被回收,那么他移动次数就会无限的累计,每次从Surior(from)到Surior(to)的过程中就相当于又增加了一次移动,当他达到一定的次数的时候(默认是15),就会移动到老年代里了,所以不存在不会被回收的对象,但是这个次数可以设置的,

-XX:MaxTenuringThreshold

就类似这样子

format,png

其实上边的这只是一种情况,还有就是如果对象太大,存不下,那就直接会进入老年代。

还有那种默认就是长期活着的也会进入老年代,

而且这种复制算法的垃圾回收机制是比较浪费内存的,每次都会有一块内存区是闲着不干活的,但是优点很明显,简单高效

以上就是GC中垃圾回收中的新生代复制算法解析,新生代的Minor GC也算是知道了不少东西了,以上就是一些个人的见解,图比较清晰,容易理解,有不对的地方希望能够各位同行指点一下。

如果你对技术提升很感兴趣,欢迎

1~5

年的工程师可以加入我的Java进阶之路来交流学习:

908676731

。里面都是同行,有

资源共享

,还有大量

面试题以及解析

。欢迎一到五年的工程师加入,合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555900.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis源码分析之(二)根据配置文件创建SqlSessionFactory(Configuration的创建过程)

SqlSessionFactoryBuilder.build创建SqlSessionFactory(粗略走一步流程) 看完上篇文章后,你对mybatis应该有个大概的了解了,那么我们知道new SqlSessionFactoryBuilder().build是框架的入口,我们到SqlSessionFactoryB…

Mybatis源码分析之(三)mapper接口底层原理(为什么不用写方法体就能访问到数据库)

mybatis是怎么拿sqlSession 在 上一篇的时候,我们的SqlSessionFactoryBuilder已经从xml文件中解析出了Configuration并且返回了sessionFactory。 然后我们要从session;中拿到sqlSession public class DefaultSqlSessionFactory implements SqlSessionFactory {pr…

mysql count distinct case when_统计符合条件的去重过的数量 - - count distinct if case

现有表结构:CREATE TABLE example_dataset (id int(11) unsigned NOT NULL AUTO_INCREMENT,tel bigint(11) DEFAULT NULL,gender varchar(11) DEFAULT NULL,PRIMARY KEY (id)) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4;插入数据INSERT INTO example_da…

Mybatis源码分析之(六)mybatis拦截器(Interceptor)的实现原理

文章目录前言InterceptorChain保存所有的Interceptor创建四大对象都走ConfigurationInterceptorChain增强对象方法Plugin封装动态代理,让你使用Mybatis拦截器更简单Invocation,让我们能在拦截器中使用动态代理类中的invoke方法中的对象调用时序图小结前言…

oauth2 java 获取token_OAuth2 Token 一定要放在请求头中吗?

Token 一定要放在请求头中吗? 答案肯定是否定的,本文将从源码的角度来分享一下 spring security oauth2 的解析过程,及其扩展点的应用场景。Token 解析过程说明当我们使用 spring security oauth2 时, 一般情况下需要把认证中心申请的 token …

java开发原则_java开发中,大家处理异常的原则是什么,是如何处理的?

展开全部最熟悉的陌生人:异常异常的类e5a48de588b63231313335323631343130323136353331333361326365型Throwable— Exception—- RuntimeException— Error需要注意的是,RuntimeException及其子类不需要在方法签名中显示注明异常抛出。例如:v…

java 线程 spring_java中spring里实现多线程

Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程的可使用ThreadPoolTaskExecutor来实现基于线程池的TaskExecutor在实际开发中由于多是异步,所以使用EnableAsync来支持异步任务,且要在Bean的方法中使用Async来声明其是一个异步任务?????…

出现503错误 怎么办

展开全部 出现503错误原因及解决办法 原因:web服务器不能处理HTTP请求,可能是临时超载或者是服务器进行维护。 解决办法:用户需要等待服务器的临时处理。在这种状态下,一些服务器可以简单的拒绝socket连接,否则会发…

java枚举类中字段有没有必要加final____枚举类字段 Field ‘xxx‘ may be ‘final‘

java枚举类中字段有没有必要加final 今天在写一个系统统一返回码的枚举类时候,突然想到一个问题,当不小心手抖给枚举类自动生成了set方法,而恰巧在用的地方不小心用了set方法,从而修改了code值,由于枚举类是天然单例&a…

MySQL数据库索引及失效场景

文章目录1. MySQL索引概述1.1 索引的概念1.2 索引的特点1.3 索引的分类1.4 索引的使用场景2. 索引失效场景2.1 索引失效9种场景2.2 索引失效场景总结3. 索引失效验证3.1 全值匹配3.2 最佳左前缀3.3 索引计算3.4 索引范围:索引列上不能有范围查询3.5 索引覆盖&#x…

getLong java_java.lang.Long.getLong()方法实例

全屏java.lang.Long.getLong(String nm) 方法确定具有指定名称的系统属性的long值。如果没有具有指定名称的属性,如果指定名称为空或null,或者该属性没有正确的数字格式,则返回null。声明以下是java.lang.Long.getLong()方法的声明public sta…

@JsonProperty注解解析

1. 概述 来源: JsonPrpperty是jackson包下的一个注解,详细路径(com.fasterxml.jackson.annotation.JsonProperty;)作用:JsonProperty用在属性上,将属性名称序列化为另一个名称。例子:public class Person{JsonProperty(value "name&qu…

java swing panel问题_关于 Java swing Box 的使用问题

代码import javax.swing.*;import java.awt.*;public class C5Ex1_2 {final static int WIDTH 400;final static int HEIGHT 400;public C5Ex1_2() {JFrame jf new JFrame("program 1");jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setSize(WIDTH, HEI…

SpringMVC注解@RequestParam全面解析____ 注解@RequestParam如何使用加与不加的区别

SpringMVC注解RequestParam全面解析 在此之前,写项目一直用的是RequestParam(value“aa” requiredfalse)这个注解,但是并不知道它的意思。现在懂了,特来记录下。 1、可以对传入参数指定参数名 1 RequestParam Stri…

@requestbody和@requestparam到底什么作用

1、什么都不写 GET 可以自动封装为对象模型,没有的数值自动为0值 POST 请求体里面放了数据,但是还是使用了RequestParam里的数据 总结: 在不使用注解的情况下,相当于默认使用了RequestParam里的数据 (这种理解是错…

linux mysql学习_Linux学习笔记(MySql操作)

忘记MySql密码:编辑mysql主配置文件 my.cnf 在[mysqld]字段下添加参数 skip-grant重启数据库服务,这样就可以进入数据库不用授权了 mysql -uroot修改相应用户密码 use mysql;update user setpasswordpassword(密码) where userroot;flushprivileges; (刷新)最后…

注解@RequestParam【不添加默认项注解】与@RequestBody的使用场景

一、前言 一直有这么一个疑问:在使用postman工具测试api接口的时候,如何使用 json 字符串传值呢,而不是使用 x-www-form-urlencoded 类型,毕竟通过 key-value 传值是有局限性的。假如我要测试批量插入数据的接口呢,使用…

SpringMVC参数的传递——接收List数组类型的数据

前言 本文主要是记录SpringMVC中当前台传过来数组的时候,如何把前台传过来的数据封装到Controller层方法的形参中。 在了解下面参数如何传递前先记住两个结论: 当Ajax以application/x-www-form-urlencoded编码格式上传数据,必须使用JSON对…

有了 IP 地址,为什么还要用 MAC 地址?

我认为,IP地址和MAC地址可以类比生活中寄快递的过程。 在整个网络中数据被封装成数据报文进行发送,就像我们生活中寄快递时将物品放进包裹中。而数据在路由器之间的跳转也可以看作是不同地区快递小哥对物流的交接。 IP地址 ip地址等价于快递包裹上的…

java运动员最佳配对_运动员最佳配对问题 - osc_y1pyjby5的个人空间 - OSCHINA - 中文开源技术交流社区...

这道题可以看为排列数的一个典型模块一、算法实现题:1、问题描述:羽毛球队有男女运动员各n人,给定2个nn矩阵P和Q。P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势;Q[i][j]则是女运动员i和男运动员j配合的女运动…