学习一:jdk-java虚拟机
名词介绍以及自我理解
你好! 这里我是经过查阅一些别人的博客学习,自己对这一块的理解认识加以记录!如果哪里描述有问题请纠正
JDK-包含了三大块
- 命令行的操作 - 如javac ,javap,java 等命令操作
- 类库- 如io socket等
- jvm虚拟机
命令行的操作
类库
JVM虚拟机
- 类加载器
- jvm虚拟机运行时内存
- 字节码执行引擎
类加载器
字节码执行引擎
JVM虚拟机运行时内存
- jvm内存
- 本地内存
本地内存(机器内存)
- 方法区(元数据区)
- 直接内存
方法区(元数据区)
- 常量(字符串常量任然在jvm内存的堆内存中开辟空间储存)
- 静态变量
- 虚拟机加载的类型信息
- 及时编译器编译后的代码
直接内存
对操作系统进行操作产生的临时内存
引用理解
直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致 OutOfMemoryError 错误出现。
JDK1.4 中新加入的 NIO(New Input/Output) 类,引入了一种基于通道(Channel)与缓存区(Buffer)的 I/O 方式,它可以直接使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆之间来回复制数据。
本机直接内存的分配不会受到 Java 堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。
JVM内存
- 堆
- java虚拟机栈
- 本地方法栈
- 程序计数器
堆
堆中存放了几乎所有的对象与数组
- 年轻代 占 1/3
- Eden 占年轻代的 8/10
经过一次gc 内存没有释放的放到Form 中去 - Form 占年轻代的 8/10
经过一次gc 内存没有释放的放到To 中去 - To 占年轻代的 8/10
共经过15次gc 内存没有释放的放到老年代中去
- Eden 占年轻代的 8/10
- 老年代 占 2/3
引用理解
Java 世界中“几乎”所有的对象都在堆中分配,但是,随着 JIT 编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。
从 JDK 1.7 开始已经默认开启逃逸分析,如果某些方法中的对象引用没有被返回或者未被外面使用(也就是未逃逸出去),那么对象可以直接在栈上分配内存。
Java 堆是垃圾收集器管理的主要区域,因此也被称作GC 堆(Garbage Collected Heap)。
从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以 Java 堆还可以细分为:
新生代和老年代;再细致一点有:Eden 空间、From Survivor、To Survivor 空间等。
进一步划分的目的是更好地回收内存,或者更快地分配内存。
java虚拟机栈(线程栈)
- 栈帧
每个方法执行都会被分配一个栈帧,栈帧进栈有先进后出的原则- 局部变量表
- 八大常量
- 引用地址
- returnAdrres
- 数据操作
- 数据进行操作时临时内存
- 动态连接
- 方法代码的引用地址
- 方法出口
- 方法结束返回的位置
- 局部变量表
本地方法栈(线程栈)
与java虚拟机栈基本相同,是本地方法栈为虚拟机使用到的native方法服务时在本地方法栈开辟栈帧,同样会有 局部变量表,数据操作,动态链接,方法出口
程序计数器(线程)
每启动一个新的线程,都会在程序计数器中分配一个专属该线程的 程序计数器
用于当字节码执行引擎执行该线程时知道执行在哪了。好继续执行。
我们我们的cpu是不停的执行各种线程的任务的
引用理解
程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。
另外,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
从上面的介绍中我们知道程序计数器主要有两个作用:
字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。
注意:程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。