jvm 内存整理 -----学习
分为:方法区 ,堆 ,栈 ,本地栈 ,程序计数器
1.程序计数器
保存当前线程执行的字节码行号指示器,解释器工作时,都是通过改变计数器的值来获取下一条程序指令,循环、异常、跳转、分支、线程恢复都要依赖程序计数器。
对于多核系统(实际一个确定时刻,cpu只能执行线程中的一条指令),线程的恢复都是通过计数器来保存的,每个线程都有自己独立的计数器,称为“线程私有的”内存。
如果线程正在执行的是java方法,则计数器记录的是当前线程的指令地址;如果执行的是本地方法,则保存的是空(undefined)。
并且计数器是java虚拟机规范中唯一一个没有规定任何OutOfMemoryError的区域,也就是没有限制。
2. java栈
与程序计数器相同,也是线程私有,生命周期与线程相同。
每个方法在执行时,都会创建个栈帧,用于保存局部变量表、操作数栈、方法入口等信息。局部变量表用于保存基本数据类型、对象引用,局部变量表一特点是在编译期间内存大小是可知的,也就是固定的。
局部变量表 是一组变量值存储空间,用于存放方法参数和方法内的局部变量
3. 本地方法栈
与java栈非常相似,不同的是java栈是为执行java方法服务的,本地方法栈是为虚拟机执行本地方法服务的
4. java堆
java堆是jvm中管理内存中最大的一块,是所有线程共享的,唯一的目的就是保存对象实例。java堆是gc回收的主要区域。java虚拟机规范规定,java堆可以处于不连续的物理内存空间,逻辑上是连续的。
5. 方法区
与java 一样,是所有线程共享的,存储已被jvm 加载的类信息、常量、静态变量、即时编译器编译后的代码,即永久代(Permanent Generation) 。
除了和java堆一样,不需要连续的物理内存空间,还可以选择不实现垃圾回收机制。虽然gc在这区域出现很少,但不代表不回收,回收目标主要是针对常量池和对类型的卸载。
6. 运行时常量池
是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容在类加载后存放在方法区的运行时常量池中。
- 字面量:较接近java语言 的常量;
- 符号引用:类和接口的全限定名;方法、字段的名称和描述符;
- 符号引用:用一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义的定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。
- 直接引用:可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用与虚拟机实现的内存布局相关,如果有了直接引用,那引用的目标必定已经在内存中存在。
--描述符:是用来描述字段的数据类型、方法的参数列表(个数、类型、顺序)和方法返回值;
7. 直接内存
直接内存并不是jvm运行时数据区的一部分,也不是jvm规范中定义的内存区域。在jdk1.4中引入的NIO,引入了一种基于通道与缓冲区的IO方式,可以使用native函数库直接使用对外内存(系统内存),然后通过java堆里的DirectByteBuffer对象作为这块内存的引用进行操作。这样能提高性能,避免了java堆和native堆中来回复制数据。