java虚拟(一)--java内存区域和常量池概念
一、java运行时数据区
也可以称为java内存区域,和java内存模型不是一回事,不要弄混,这里基于jdk1.8之前
1.1、方法区
线程共享,类装载过程中产生的java.lang.Class对象保存在方法区,而不是堆,请参考《深入理解java虚拟机》P215
jdk1.8之前HotSpot通过永久带实现方法区,为了把GC可以像堆一样管理内存,能够复用代码,1.8移除永久带,通过本地内存实现方法区,
其他虚拟机没有永久带的概念,因为更容易出现内存溢出
主要存放类信息、常量、静态变量、即时编译后的代码等
垃圾回收主要是针对常量池回收和类型的卸载,这块区域的回收很难,尤其是类型卸载,可以选择不进行垃圾回收,但是回收很有必要的
PS:jdk1.8及以后,方法区被移除,通过元空间实现,而元空间使用的是直接内存,可以使用参数:-XX:MetaspaceSize
来指定元数据区的大小
1.2、虚拟机栈
线程私有,生命周期和线程相同,每执行一个方法都会创建一个栈帧,从执行到结束,对应着栈帧在虚拟机栈的入栈到出栈过程,可以类比
数据结构中的栈,java方法两种返回方式:
1、return语句
2、抛出异常
这两种方式都会导致栈帧被弹出
栈帧:
保存着局部变量表、操作数栈、方法出入口等
局部变量表:
用来保存方法参数和返回值,也就是基本数据类型、对象的引用、returnAddress类型(指向一个字节码指令的地址)
double和long占用两个局部变量空间(variable slot),其余占用1个,slot空间大小在编译期间就确定,方法运行期间无法改变
PS:可能出现Stack OverflowError、OutOfMemoryError错误
1.3、本地方法栈
线程私有,和虚拟机栈相似,一个为Java方法服务,一个为了本地方法服务,本地方法栈中方法实现的语言、方式等没有规定,由具体的虚拟机
确定,在HotSpot中只有栈,没有虚拟机栈和本地方法栈的区别。
本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。
PS:可能出现Stack OverflowError、OutOfMemoryError错误
1.4、堆
线程共享,这是虚拟机内存最大的一块区域,也是GC的主要区域,几乎所有的对象和数组都保存在这里
内存回收的角度分为:
新生代:Eden Space、From Survivor、To Survivor
老年代:
1、主要用来保存大对象(可以通过-XX:PretenureSizeThreshold 设置大对象的阀值)
2、或者从新生代经过15次 minor GC存活下来的对象(-XX:MaxTenuringThreshold)
3、第二条不是绝对的,VM动态判断,如果Survivor空间中相同年龄所有对象大小的综合大于Survivor空间的一半,年龄大于或等于该
年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold要求的年龄
默认Eden Space:From Survivor:To Survivor=8:1:1,可以通过-XX:SurvivorRatio调节,一般不需要新生代和老年代默认是1:2,
可以通过-XX:NewRatio调节
PS:进一步划分的目的是更好地回收内存,或者更快地分配内存。
1.5、程序计数器
线程私有,是一块很小的内存区域,记录着当前虚拟机字节码指令的地址(对于JNI,值为undefined),字节码解释器通过改变计数器的值来
选择下一条执行的字节码,分支、循环、跳转、异常处理、线程恢复等功能都要依靠计数器。
线程上下文切换的时候,为了能够恢复到正确的执行位置,需要每个线程都拥有一个独立的线程计数器,互不影响。
PS:唯一一个没有规定OOM的区域
1.6、直接内存
不属于Java内存区域,有可能出现OOM,jdk1.4出现了NIO,它可以通过Native函数库分配堆外内存,通过Java堆中的DirectByteBuffer对象
作为引用进行操作,在某些场景明显提高性能,以为避免了Java堆和Native堆来回复制数据。
直接内存的分配不受Java堆大小限制,而是收到本机总内存的限制。
1.7、本地内存
就是JMM的概念了,后面写JMM的时候再讲
二、常量池
2.1、字符串常量池
在HotSpot中通过StringTable类实现功能,StringTable是一个hash表,默认长度大小1009,被所有类共享。字符串常量由字符组成,保存在
StringTable上面。在jdk1.6当中,StringTable的长度是固定1009,如果存放在StringTable中的字符串很多,造成hash冲突的几率很大,链表过
长,当通过String.intern()查找String Pool时,性能就会降低。
在jdk1.7当中,StringTable的长度可以通过-XX:StringTableSize设置
存放的内容:
String.intern()主要是为了复用字符串常量,节省内存空间
在jdk1.6及以前的版本,存放的都是字符串常量,使用""声明的字符串都存储在这,例如:String str = "abc";
在jdk1.7之后,String.intern()发生变化,返回对象的引用,因此除了字符串常量,也可以存放堆中字符串常量的引用
PS:在jdk1.7之后,字符串常量池从方法区转移到堆中
2.2、class常量池
首先java代码通过javac编译成class文件,class文件中保存着类的相关信息(版本,类、字段、方法、接口等信息),除此之外,还有Class
常量池,用来存放编译器产生的各种字面量(Literal)和符号引用(Symbolic References),每个class文件都有一个class常量池。
字面量:1.String 2.基本数据类型 3.声明final的常量
符号引用:1.类和方法的全限定名(类似于com.cfets.**.**这种) 2.字段的名称和描述符 3.方法的名称和描述符
2.3、运行时常量池
就是class常量池被加载到方法区之后的版本,区别就是:字面量可以通过String.intern()动态添加,符号引用解析为直接引用(类加载的
解析阶段)
当类加载到内存之中,jvm会把class常量池的内存存放到运行时常量池,所以,运行时常量池也是每个class都有的。
符号引用:上述有说明。以一组符号来描述所引用的目标,只要能定位到目标,无论是任何形式的字面量,和jvm实现的内存布局无关。
直接引用:直接指向目标的指针、相对偏移量或者间接定位到目标的句柄,句柄和指针对应对象的访问定位方式,和jvm实现的内存布局有关。
PS:JDK1.7及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池
java虚拟(一)--java内存区域和常量池概念的更多相关文章
- Java中常用的内存区域
在Java中主要存在4块内存空间,这些内存空间的名称及作用如下. 1. 栈内存空间: 保存所有对象名称(更准确的说是保存了引用的堆内存空间的地址). 2. 堆内存空间: 保存每个对象的具体属性内容 ...
- java中的堆、栈、常量池
java中的堆.栈.常量池 分类: java2010-01-15 03:03 4248人阅读 评论(5) 收藏 举报 javastring编译器jvm存储equals Java内存分配: 1. 寄存器 ...
- 详细介绍Java中的堆、栈和常量池
下面主要介绍JAVA中的堆.栈和常量池: 1.寄存器 最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈 存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在 ...
- JVM学习笔记(一):Java虚拟机和虚拟机内存区域
为什么Java程序需要运行在虚拟机上 因为Java在设计之初的跨平台特性,我们知道Java程序是运行在Java虚拟机上的.如果你要问为什么Java程序要运行在虚拟机上,我可以反问你几个问题. 为什么买 ...
- Java虚拟机运行时内存区域简析
figure:first-child { margin-top: -20px; } #write ol, #write ul { position: relative; } img { max-wid ...
- 【java】JVM的内存区域划分
学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的呢? 由于Java程序是交由JVM执行 ...
- java运行时的内存区域
1.概述 java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线 ...
- java中的常用内存区域总结
<开发实战经典> (1)栈内存空间:保存所有的对象名称 (2)堆内存空间:保存每个对象的具体属性内容 (3)全局数据区:保存static类型的属性 (4)全 ...
- Java内存中的常量池
1,java内存模型简介 <深入理解java虚拟机>里将java内存分为如下五个模块: 堆-堆是所有线程共享的,主要用来存储对象. 其中,堆可分为:新生代和老年代两块区域.使用NewRat ...
随机推荐
- 剑指offer面试题24-二叉搜索树的后序遍历序列
题目: /* * 输入一个整数数组,推断该数组是不是某二叉搜索树的兴许遍历的结果.<br/> * 假设是则返回true,否则返回false.<br/> * 如果输入的数组 ...
- Spark技术内幕:Master基于ZooKeeper的High Availability(HA)源代码实现
假设Spark的部署方式选择Standalone,一个採用Master/Slaves的典型架构,那么Master是有SPOF(单点故障,Single Point of Failure).Spark能够 ...
- 怎样在gluster的源代码中加入自己的xlator
本文并不说明怎样编写一个xlator.在glusterfs3.6.1下验证成功 目标在glusterfs-3.6.1/xlators/debug/下建立一个自己的xlator库并能够统一安装到系统文件 ...
- [计算机故障]excel无法存盘,总是自动重启恢复
同事的excel文档,无法保存.总是提示什么要发送错误报告.错误报告中的错误信息包含event type:BXE.这个文件大小约1M多.工作簿中包含表大约有30张,表名称为中文.我去看了看,其他电子表 ...
- data-toggle data-target
data-toggle https://stackoverflow.com/questions/30629974/how-does-the-data-toggle-attribute-work-wha ...
- ZOJ3965 Binary Tree Restoring
ZOJ3965 给定一颗二叉树的两种DFS序列 输出一种可能的二叉树的结构. 考察树的递归性质,不要想的太复杂. 当前节点在两个串中后面的节点假如不同则能确认两个子树,如果相同则把下个点作当前点的一个 ...
- 31. ExtJs4回车事件监听
转自:https://710542316.iteye.com/blog/2148542 监听表单字段事件: Ext使得对用户某个动作的监听特别简单,诸如单击某个元素或者按下某个键盘上的键. 一个经常性 ...
- [Swift通天遁地]一、超级工具-(9)在地图视图MKMapView中添加支持交互动作的标注图标
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- SpringBoot2.x版本整合SpringSecurity、Oauth2进行password认证
很多人在进行项目开发时都会用到Oauth2.0结合SpringSecurity或者Shiro进行权限拦截以及用户验证,网上也有很多的案例,前几天项目里边需要用到,顺便整合了进来,特此写篇博客,记录下过 ...
- 编写第一Spring程序
构建Spring项目 通过https://start.spring.io/来构建项目,在这里我选择了两个依赖,web 和 Actuator. 项目结构 通过eclipse导入项目,可以看到这是一个标准 ...