JVM学习(学习中,同步更新)

作者: 秋波未央 | 来源:发表于2019-12-11 21:45 被阅读0次

1.什么是JVM?

定义:Java Virtual Machine-java 程序的运行环境(二进制字节码的运行环境)

优点:1.一次编码,到处运行。

2.自动内存管理,垃圾回收功能。

3.数组下标越界越界检查

4.多态

比较:

JVM学习(学习中,同步更新)

作用:1.面试2.理解底层的实现原理(长远发展必过)3.中高级程序员必备技能。

学习路线

JVM学习(学习中,同步更新)

一.内存结构

1.程序计数器(寄存器)

Program Counter Register

运行过程:

二进制编码—>解释器—>机器码—>CPU

作用:记住下一条jvm指令的执行地址,如果没有它将不知道执行哪条指令

特点:1.是线程私有的2.不会存在内存溢出

二.虚拟机栈(线程运行时需要的内存空间)

JVM学习(学习中,同步更新)

栈帧:一个栈帧对应一个方法的调用,是每个方法运行时需要的内存

注意:每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。

问题辨析:

1.垃圾回收是否涉及栈内存?

答:不涉及。

2.栈内存分配越大越好么?

答:栈内存越大,可运行的线程数越少,所以并不是越大越好。

3.方法内的局部变量是否线程安全?

答:局部变量是线程私有的,不会受到其它线程的干扰。

扩展:若为 static int x=0.多线程共享这个数,不加操作就会产生混乱,要考虑线程安全性。

总结:线程是否安全,要看变量是否共享,是否逃离了方法的作用范围(例:有return返回值的方法)

栈内存溢出:

1.栈帧过多导致的(一般)

2.栈帧过大导致

运行错误:java.lang.StackOverflowError.

线程运行诊断:

案例1:cpu占用过多

解决方式:定位到占用线程过高的那个线程,结束进程。

案例2:程序运行长时间没结束

解决方式:造成原因是两个线程产生了死锁,释放线程的锁就解决了。

3.本地方法栈:给本地方法提供一个运行的空间

三.堆

定义:通过关键字new创建的对象都会使用堆内存

特点:

1.它是线程共享的,堆中对象都需要考虑线程安全的问题。

2.有垃圾回收机制。

堆内存的溢出:

报错代码:java.lang.OutofMemoryError:Java heap space

对堆空间设置参数:-Xmx_m(_上填要设置的值)

注:堆空间可以设置小一点,这样可以尽快解决关于堆内存产生的问题。

堆内存诊断:

1.jps工具

查看当前系统中有哪些java进程

2.jmap工具

查看堆内存占用情况。heap 进程id

3.Jconsole工具

图形界面的,多功能的检测工具,可以连续监测。

案例:垃圾回收后内存任然占用很高

分析:对象一直被引用,未能回收。


四.方法区

定义:是所有java虚拟机线程共享的区,它存储了与类相关的一些信息(成员变量、方法数据、成员方法、构造器的方法、类的构造器)

注解:方法区是在虚拟机启动时被创建,逻辑上是堆的一个组成部分,但要注意的是不同厂商制作的都有些许差异。

方法区图解:

                    JVM内存结构1.6图解

JVM学习(学习中,同步更新)

由图可知:在1.6中,方法区的实现叫永久代,String Table叫字符串表(俗称:串池)

              JVM内存结构1.8图解

JVM学习(学习中,同步更新)

对比:在1.8中,方法区的实现变成了MetaSpace,将不再占用堆内存了,换句话说它已经不是由JVM管理它的内存结构了,它已经被移动到本地内存(操作系统内存)当中,同时StringTable被移到了Heap中。

方法区内存溢出

类加载器的作用:加载类的二进制字节码。

1. 内存结构1.8以前会导致永久代内存溢出

永久代内存溢出报错:

Java.lang.OutofMemoryError:PermGen space

2. 内存结构1.8之后会导致元空间内存溢出

元空间内存溢出报错:

Java.lang.OutofMemoryError:Metaspace

实际场景内存溢出辨析:

当一些项目用到Spring框架和mybatis框架时,经常会产生大量的在运行期间生成的类。(在1.8以前常出现)

常量池作用:给指令提供一些常量符号,根据常量符号去找到对应的类名、方法名、参数类型、字面量等信息。

补充:二进制字节码(类的基本信息、常量池、类方法定义、包含了虚拟机指令)

运行时常量池,常量池是*.Class文件中的,当该类被加载时它的常量池信息就会放入运行时的常量,并把里面的符号地址变为真实地址。


五.StringTable特性

1.常量池中的字符串仅是符号,第一次用到时才变为对象

2.利用串池的机制,来避免重复创建字符串对象

3.字符串常量拼接的原理是编译期优化

注:拼接的仅存在于堆中,串池中没有

4.字符串常量拼接的原理StringBuilder(1.8)

5.可以使用intern主动将串池中还没有的字符串对象放入串池

例:

String s=newString("a")+newString("b");

//new String("ab")

String s2=s.intern();

//将这个字符串对象尝试放入串池,如果有则不会放入,如果没有则放入串池,会把串池中的对象返回。

System.out.println(s2=="ab");

//运行结果为true,因为“ab”这个对象在之前已经被放入串池中了,因此不会创建新的对象,所以s2的对象就是“ab”

System.out.println(s=="ab");

//运行结果为true,因为intern将s的对象“ab”放入了串池中,并把“ab”返回给了s,所以s的对象就是“ab”

相关文章

网友评论

    本文标题:JVM学习(学习中,同步更新)

    本文链接:https://www.haomeiwen.com/subject/htgagctx.html