JVM系列一

 一、

JVM由三部分组成:类加载子系统、执行引擎、运行时数据区。

1. 类加载子系统,可以根据指定的全限定名来载入类或接口。

2. 执行引擎,负责执行那些包含在被载入类的方法中的指令。

3. 当程序运行时,JVM需要内存来存储许多内容,例如:字节码、对象、参数、返回值、局部变量、运算的中间结果,等等,JVM会把这些东西都存储到运行时数据区中,以便于管理。而运行时数据区又可以分为方法区、堆、虚拟机栈、本地方法栈、程序计数器。

加分回答

    运行时数据区是开发者重点要关注的部分,因为程序的运行与它密不可分,很多错误的排查也需要基于对运行时数据区的理解。在运行时数据区所包含的几块内存空间中,方法区和堆是线程之间共享的内存区域,而虚拟机栈、本地方法栈、程序计数器则是线程私有的区域,就是说每个线程都有自己的这个区域。

二、

JVM内存结构

类→方法区

实例对象→堆

调用的方法→虚拟机栈、程序计数器、本地方法栈

三、

1、程序计数器(Program Counter Register)(寄存器)

作用:是记住下一条jvm指令的执行地址

特点:是线程私有的,唯一一个不会存在内存溢出的区

2、栈

作用:线程运行时需要的内存空间

由多个栈帧组成(栈帧:每个方法运行时需要的内存)(参数、局部变量、返回地址)

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

(2)方法的局部变量是否线程安全?

如果方法内局部变量没有逃离方法的作用访问,他是线程安全的

如果局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

(3)栈内存溢出

栈帧过大导致栈内存溢出

栈帧过多,导致栈内存溢出

(方法递归的调用)

线程运行诊断:定位,用 top 定位哪个进程对cpu占用过高

cpu占用过多:用 ps 命令定位哪个线程对cpu占用过高,JDK提供的工具看哪一个线程:jstack进程id(可以根据线程id找到有问题的线程,进一步定位到有问题代码的源码行号)

java程序运行很长时间无结果:发生了死锁

(4)通过native等去调用本地方法的接口:本地方法栈:为本地方法的运行提供一个空间(本地方法的接口:c语言书写的底层)

3、堆(Heap)

(1)堆和方法区是线程共享的,需要考虑线程安全的问题

(2)有垃圾回收机制

(3)堆内存溢出:不断产生对象,并不断使用着这些对象

OutofMemoryError:java heap space  (报错文)

(4)堆内存诊断

jps工具:查看当前系统中有哪些java进程

jmap工具:查看堆内存占用情况

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

(5)内存回收后:内存占用率依然很高?

Terminal:       jps:    jmap-heap  17748

Edenspace: 内存区的占用(新生代)  old generation 老年代

jconsole:连接到进程,执行GC

可能存在一些编程失误,导致一些对象始终被调用而无法释放内存

可用  jvitualvm  可视化展示虚拟机内容

4、方法区

(1)与类的结构相关的一些信息(成员变量、方法数据、成员方法、构造器方法、特殊方法:类的构造器      运行时常量池)

(2)在虚拟机启动时被创建,逻辑上是堆的组成部分

(3)方法区内存溢出:

类加载器:可以用来加载类的二进制字节码(二进制字节码  (类的基本信息、常量池、类方法定义)  包含了虚拟机的指令)

1.8以前是永久代(permGenspace)空间导致的方法区内存溢出,1.8之后是(metaspace)元空间导致的

4、运行时常量池 

常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息

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

你可能感兴趣的:(jvm,java,开发语言)