JVM从入门到深入理解(一)——JVM内存结构

!!!声明:这仅仅是一个人学习笔记,参考了百度的大量现有的博客文字叙述拼接在一起,并非原创!!!

〇、世界观。

(一)JAVA程序本身是不能直接在计算机上运行的,它需要依赖于硬件基础之上的操作系统和JVM(JAVA虚拟机)。

(二)JAVA程序启动时JVM都会分配一个初始内存和最大内存给这个应用程序。这个初始内存和最大内存在一定程度上会影响应用程序的性能。

(三)JVM其实就是操作系统上的一个普通程序(进程名叫java,这个程序可以解释执行class文件,系统中当前运行了多少个java程序就会有多少个java进程)。当java进程启动时会首先分配一块堆内存(最小内存),以后每当java程序要求JVM(java进程)分配内存时,JVM就会在预先分配的那块内存上为java程序分配内存,当预先分配的那块内存用完时,JVM会再向操作系统要内存(物理内存),但是JVM不会无限制的向操作系统要内存,当它占用的实际内存达到一个预定值(最大可用内存)时,如果java程序还向JVM要内存,并且JVM无法通过垃圾回收机制回收当前堆中的内存来为java程序服务时,它就会给程序抛出异常:java.lang.OutOfMemoryError。其中内存回收时机并不是在用掉内存达到最大可用内存时才进行,它的运行时机是不确定的。可见JVM的最大可用内存就是java程序能够使用的最大内存。
例如:我们把某JAVA程序的JVM最大可用内存设为200M,而我们的物理内存是1G。这种情况下,我们的java程序最多能使用200M内存,虽然我们可能还有800M的内存可用,但是当我们的程序用掉200M后,如果再要内存,JVM不会因为我们还有800M的内存而为我们分配内存,它会抛出java.lang.OutOfMemoryError异常。

(四)Java代码查看内存方法。
Runtime run = Runtime.getRuntime();
System.out.println(“JVM最大的内存量” + run.maxMemory() +“字节”);
System.out.println(“JVM的空闲内容量” + run.freeMemory() +“字节”);

一、JVM内存结构。

(一)、总体结构。

Java虚拟机在执行Java程序的过程中会把它管理的内存划分成若五个不同的数据区域。
在这里插入图片描述
1、线程私有
各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
(1)程序计数器
(2)虚拟机栈
(3)本地方法栈

2、线程共享
(1)堆
(2)方法区

(3)直接内存(一般没被考虑??)

3、运行时数据区
运行时数据区就是java内存管理,java能管理的地方只在java运行时数据区,其他无法控制,而java运行时数据区的大小,可根据自己的需求自行更改,但在其中,有些数据区是数据共享,有些数据区是对象独享,在整个操作中,对于运行时数据区直接和java的线程对象关联,所以,我们所说的java内存调优都是在运行时数据区进行的。

即,共享的数据区越大越好。所以,关键是在堆内存中,如果我们要真正做到对程序的理解,就需要对堆内存进行一定的控制。

(二)、程序计数器。(Program Counter Register)

1、程序计数器是一块较小的内存空间,可看作是当前线程所执行的字节码的信号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。

2、另外,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器。

(三)、虚拟机栈。(JVM Stacks)

1、与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期和线程相同,描述的是Java方法执行的内存模型。
在这里插入图片描述2、每个线程都会有自己的调用,此时,每个线程都要有自己独立的空间,所以,每个栈内存都是线程私有的。我们在java JVM 中用栈帧(Stack Frame)来定义栈的数据,每一个栈帧表示每个可能执行的方法。
在这里插入图片描述3、栈帧中则包含了:局部变量表,操作树栈,指向运行时常量池的引用,方法返回地址和动态链接。

(1)Java内存可以粗糙的区分为堆内存(Heap)和栈内存(Stack),其中栈就是现在说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。

局部变量表主要存放了编译器可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不同于对象本身,可能是一个指向对象起始地址的引用指向,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。

局部变量表是方法的局部变量或形参,其以变量槽(solt)为最小单位,只允许保存32为长度的变量,如果超过32位则会开辟两个连续的solt(64位长度,long和double);

(2)操作数栈(Operand Stack):表达式计算在栈中完成;

(3)指向当前方法所属的类的运行时常量池的引用(Reference to runtime constant pool):引用其他类的常量或者使用String 池中的字符串;

(4)方法返回地址(Return Address):方法执行完后需要返回调用此方法的位置,所以需要再栈帧中保存方法返回地址。

4、当产生一个方法调用的时候,原本的方法会入栈,当方法执行完毕之后,方法将会进行栈帧的出栈,这样就能定义每个栈的详细信息。

5、在Java 虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常;如果虚拟机栈可以动态扩展(当前大部分的Java 虚拟机都可动态扩展,只不过Java 虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError 异常。

(四)、本地方法栈。(NM Stacks)

和虚拟机栈作用非常相似,区别是: 虚拟机栈为虚拟机执行Java方法 (字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。 (在HotSpot虚拟机中和Java虚拟机栈合二为一?)

(五)、堆。(Heap)

1、JVM所管理的内存中最大的一块,Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。

2、Java堆是垃圾收集器管理的主要区域,因此也被称作GC堆(Garbage Collected Heap)。从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以Java堆还可以细分为新生代老年代,再细致一点有:Eden空间、From Survivor、To Survivor空间等。进一步划分的目的是更好地回收内存,或者更快地分配内存

3、堆中数据未指向后是稍后GC随机清除。局部变量在栈内存中,成员变量在堆内存中。栈中数据使用完就立即释放,这个也说明了局部变量不会相互影响。
在这里插入图片描述

(六)、方法区。(Method Area)

1、方法区与 Java 堆一样,是各个线程共享的内存区域。

2、用于存储已被虚拟机加载的类信息常量静态变量即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。

3、定义方法时候,方法在方法区内存中。调用方法时,方法存在栈内存中,调用完后直接在栈中清除内存了。

4、运行时常量池(Runtime Constant Pool)
(1)运行时常量池是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池信息(用于存放编译期生成的各种字面量和符号引用)。
(2)既然运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量池无法再申请到内存时会抛出 OutOfMemoryError 异常。
(3)JDK1.7及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。同时在 jdk 1.8中移除整个永久代,取而代之的是一个叫元空间。Metaspace的区域。

5、了解(HotSpot虚拟机中方法区也常被称为 “永久代”,本质上两者并不等价。仅仅是因为HotSpot虚拟机设计团队用永久代来实现方法区而已,这样HotSpot虚拟机的垃圾收集器就可以像管理Java堆一样管理这部分内存了。但是这并不是一个好主意,因为这样更容易遇到内存溢出问题。相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入方法区后就“永久存在”了。)

(七)、直接内存。(Direct Memory)

1、直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError 异常出现,所以我们放到这里一起讲解。
2、JDK1.4中新加入的NIO(New Input/Output)类,引入了一种基于通道(Channel) 与缓存区(Buffer) 的I/O方式,它可以直接使用Native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为避免了在Java堆和Native堆之间来回复制数据。
3、本机直接内存的分配不会受到Java堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。

二、参考原文。

(1)https://www.cnblogs.com/winby/p/6627838.html
(2)https://blog.csdn.net/qq_34337272/article/details/81875700
(3)https://blog.csdn.net/qq_34707744/article/details/79278169

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值