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 ...
随机推荐
- linux 下查看一个进程执行路径
在linux下查看进程大家都会想到用 ps -ef|grep XXX 但是看到的不是全路径.怎么看全路径呢? 每一个进程启动之后在 /proc以下有一个于pid相应的路径 比如:ps -ef|grep ...
- java并发编程之Semaphore
信号量(Semaphore).有时被称为信号灯.是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们可以正确.合理的使用公共资源. 一个计数信号量.从概念上讲,信号量维护了一个许可集.如 ...
- 关于jiffies回绕以及time_after,time_before
系统中有非常多变量用来记录一个单调递增的现实,典型的有两个,一个是TCP的序列号.还有一个就是jiffies,可是由于计算机内表示的数字都是有限无界的,所以不论什么数字都不能做到全然意义的单调递增,它 ...
- Python开发【第*篇】【Xpath与lxml类库】
什么是XML XML 指可扩展标记语言(EXtensible Markup Language) XML 是一种标记语言,很类似 HTML XML 的设计宗旨是传输数据,而非显示数据 XML 的标签需要 ...
- Android学习笔记-保存数据的实现方法2-SharedPreferences
Android下,数据的保存,前面介绍过了,把数据保存到内存以及SD卡上,这次我们就介绍一下,更为常用的采用SharedPreferences的方式来保存数据, 1,得到SharedPreferenc ...
- Android实现多个倒计时优化与源代码分析
由于之前有个项目需求是须要时时刻去更新UI倒计时,之前想到的,这简单嘛,用计时或者Handler就能够搞定,并且性能也不错,可是需求要ListView,什么,?大量的View都须要,那Handle处理 ...
- JavaScript实现页面重载 - 535种方式
location = location ... and a 534 other ways to reload the page with JavaScript location = location ...
- 第二步:将LAD结果的属性值二(多)值化,投入计算模型
一文详解LDA主题模型 - 达观数据 - SegmentFault 思否 https://segmentfault.com/a/1190000012215533 SELECT COUNT(1) FRO ...
- 以太网接口TCP/IP协议介绍,说的很容易懂了
以太网接口TCP/IP协议介绍,说的很容易懂了 TCP/IP协议,或称为TCP/IP协议栈,或互联网协议系列. TCP/IP协议栈(按TCP/IP参考模型划分) 应用层 FTP SMTP HTT ...
- oracle存储过程和游标的使用
oracle存储过程和游标的使用 (2011-04-19 14:52:47) 转载▼ 游标: 用来查询数据库,获取记录集合(结果集)的指针,我们所说的游标通常是指显式游标,因此从现在起没有特别指明的情 ...