Java虚拟机,GC垃圾回收机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wang_yong_hui_1234/article/details/78492391

一,Java内存区域

1,用一张图来表示内存区域

这里写图片描述

2,线程隔离的数据区(线程私有内存区域,线程之间互不影响)

①,程序计数器:是一块较小的内存空间,可以看成是当前线程所执行的字节码的行号指示器。如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值为(Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
②,Java虚拟机栈:它的生命周期与线程相同。每个方法在执行时会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接等。每个方法从执行到完成的过程,就对应着一个栈帧在虚拟机栈中的入栈到出栈的过程。Java虚拟机栈规定了两个异常:StackOverflowError异常和OutOfMemoryError异常。
③,本地方法栈:它和Java虚拟机栈的区别,虚拟机栈为虚拟机提供Java方法服务,本地方法栈为虚拟机提供Native方法服务。本地方法栈规定了两个异常:StackOverflowError异常和OutOfMemoryError异常。

注意:当线程请求的内存大小大于所配置的初始化大小,将抛出StackOverflowError。比如配置大小为128M,而栈里的内存分配超过了这个大小,通常发生在方法递归调用深度过大时候;如果JVM内存大小是可扩展的,当然一般都是可以扩展的,当自动扩展到计算机本身内存大小时会抛出OutOfMemoryError。比如内存为4G,当JVM超过配置大小自动扩展至4G时会抛出OutOfMemoryError。

3,共享数据区
①,Java堆:是Java虚拟机管理的内存中最大的一块,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,是垃圾收集器管理的主要区域。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,会抛出OutOfMemoryError。
②,方法区:此内存区域用于存储已被虚拟机加载的类信息,常量,静态变量等数据。

4,运行时常量池
运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。

5,直接内存
直接内存不是虚拟机运行时数据区的一部分,Buffer缓冲区就是直接内存,它可以使用Native函数库直接分配堆外内存。虽然直接内存不会受到Java堆大小的限制,但是,会收到本机总内存大小以及处理器寻址空间的限制。

二,垃圾收集器与内存分配策略

1,简单介绍垃圾收集器
Serial收集器,ParNew收集器,Parallel Scavenge收集器,Serial Old收集器,Parallel Old收集器,CMS收集器,G1收集器
2,内存分配
①,Java 程序运行时的内存分配策略有三种,分别是静态分配,栈式分配,和堆式分配,对应的,三种存储策略使用的内存空间主要分别是静态存储区(也称方法区)、栈区和堆区。
②,静态存储区(方法区):主要存放静态数据、全局 static 数据和常量。这块内存在程序编译时就已经分配好,并且在程序整个运行期间都存在。
③,栈区 :当方法被执行时,方法体内的局部变量(其中包括基础数据类型、对象的引用)都在栈上创建,并在方法执行结束时这些局部变量所持有的内存将会自动被释放。因为栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
④,堆区 : 又称动态内存分配,通常就是指在程序运行时直接 new 出来的内存,也就是对象的实例。这部分内存在不使用时将会由 Java 垃圾回收器来负责回收。

三,虚拟机性能监控与故障处理工具

JDK安装目录bin中有很多工具,这里就介绍几个

1,JDK监控和故障处理工具(命令行工具)
①,jps:JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程
②,jstat:JVM Statistics monitoring Tool,用于手机HotSpot虚拟机各方面的运行数据
③,jinfo:Configuration Info for Java,显示虚拟机配置信息
④,jmap:Memory Map for Java,生成虚拟机的内存转储快照(heapdump文件)
⑤,jhat:JVM Heap Dump Browser,用于分析heapdump文件,它会建立一个HTTP/HTML服务器,让用户可以在浏览器上查看分析结果
⑥,jstack:Stack Trace for Java,显示虚拟机的线程快照

2,JConsole:Java监视与管理控制台
Jconsole是一种基于JMX的可视化监视,管理工具。通过JDK/bin中的“jconsole.exe”可以启动,启动之后可以双击一个进程,也可以连接远程进程,对远程虚拟机进行监控

这里写图片描述

Jconsole主页面,可以看到概览,内存,线程,类等信息

这里写图片描述

四,内存模型

Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样底层细节。此处的变量与Java编程时所说的变量不一样,指包括了实例字段、静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,后者是线程私有的,不会被共享。

1,主内存与工作内存
这里讲的内存模型和上边讲的Java内存区域没有关系,这里内存模型偏向于硬件。Java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存(可以与前面将的处理器的高速缓存类比),线程的工作内存中保存了该线程使用到的变量到主内存副本拷贝,线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成,线程、主内存和工作内存的交互关系如下图所示

这里写图片描述

2,内存间交互操作

①,内存间交互即一个变量如何从主内存拷贝到工作内存,从工作内存同步回主内存。Java内存模型定义了8中变量

  • lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。
  • unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
  • read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
  • load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
  • use(使用):作用于工作内存的变量,它把工作内存中的一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的字节码指令时将会执行这个操作。
  • assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节指令时执行这个操作。
  • store(存储):作用于工作内存的变量,它把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作使用。
  • write(写入):作用于工作内存的变量,它把store操作从工作内存中得到的变量的值放入住内存的变量中。

②,这些变量是如何执行的呢?如果要把一个变量从主内存复制到工作内存,那就要顺序执行read和load操作,如果要把变量从工作内存同步回主内存,就要顺序执行store和write操作。注意,Java内存模型只要求上述两个操作必须按顺序执行。

③,Java内存模型还规定了在执行上述8种操作时必须满足如下规则:

  • 不允许read和load,store和write操作之一单独出现,即不允许一个变量从主内存读取了但工作内存不接受,或者从工作内存发起回写了但主内存不接收的情况出现。
  • 不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须该变化同步回主内存。
  • 不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存中。
  • 一个新的变量只能在主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话,就是对一个变量实施use,store操作之前,必须先执行过了assign和load操作。
  • 一个变量在同一个时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。
  • 如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
  • 如果一个变量事先没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许去unlock一个被其它线程锁定住的变量。
  • 对一个变量执行unlock操作之前,必须先把此变量同步回主内存(执行store,write操作)。

猜你喜欢

转载自blog.csdn.net/wang_yong_hui_1234/article/details/78492391